Improve protections again and player database (#606)
This commit is contained in:
parent
ffa2d74b60
commit
ab49103171
@ -3,7 +3,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
gtav_classes
|
||||
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
|
||||
GIT_TAG 0a23b823e2dd2e52004b206b7cce735d326c209f
|
||||
GIT_TAG 1dc66fb37fec895c96c2b1e4944e382a83c5e993
|
||||
GIT_PROGRESS TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -7,7 +7,7 @@ namespace big
|
||||
{
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 08 00 ? 38 00 5D ? ? ? 2A 06", 5, {0x6E, 0x2E, 0x01, 0x01}, &g->session.decloak_players });
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 04 00 ? 2C ? ? ? 5D ? ? ? 6E 57 ? ? 2C", 5, { 0x2E, 0x01, 0x00 }, &g->protections.script_host_kick });
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 00 07 00 00 5D ? ? ? 56 ? ? 6E ", 5, { 0x2E, 0x00, 0x00 }, &g->tunables.no_idle_kick });
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 08 00 00 5D ? ? ? 56 ? ? 6E ", 5, { 0x2E, 0x01, 0x00 }, &g->tunables.no_idle_kick });
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating
|
||||
g_script_patcher_service->add_patch({ RAGE_JOAAT("shop_controller"), "2D 01 04 00 00 2C ? ? ? 56 ? ? 6E ", 5, { 0x6E, 0x2E, 0x01, 0x01 }, nullptr }); // despawn bypass
|
||||
|
||||
|
30
src/core/data/block_join_reasons.hpp
Normal file
30
src/core/data/block_join_reasons.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
inline std::unordered_map<int, const char*> block_join_reasons =
|
||||
{
|
||||
{ 1, "None" },
|
||||
{ 5, "Been Voted Out" }, // You have already been voted out of this game session.
|
||||
{ 7, "Incompatible Assets" }, // Failed to join session due to incompatible assets.
|
||||
{ 8, "Session Full" }, // The session you're trying to join is currently full.
|
||||
{ 9, "Slot Full" }, // The session you're trying to join is currently full of players.
|
||||
{ 10, "No Title Update" }, // Please make sure all players have the latest Title Update.
|
||||
{ 12, "Invites Disabled" }, // Invites are currently disabled in the session.
|
||||
{ 13, "Different Targeting Mode" }, // The session you are trying to join is using a different targeting preference. You can change your preference in the Settings tab of the Pause Menu in Grand Theft Auto V. Joining a new GTA Online Session.
|
||||
{ 14, "Cheater" }, // You are classed as a cheat and can only play with other cheats until you are forgiven.
|
||||
{ 16, "Incompatible DLC" }, // Incompatible downloadable content. All players must have the latest compatibility pack.
|
||||
{ 17, "Crew Only" }, // You are trying to enter a Crew Members only session.
|
||||
{ 21, "Session No Longer Exists" }, // The session you are trying to join no longer exists.
|
||||
{ 22, "Invite Only" }, // The session you are trying to join is private. You will need to be invited to join this session.
|
||||
{ 26, "Friends Only" }, // The session you are trying to join is friends only.
|
||||
{ 23, "Different Build Type" }, // The session you are trying to join is a different build type.
|
||||
{ 25, "Different Content" }, // The session you are trying to join is not using the same content.
|
||||
{ 18, "Bad Sport" }, // The session you are trying to join is for people who are not Bad Sports or cheaters - you are a Bad Sport.
|
||||
{ 19, "Bad Sports Only" }, // The session you are trying to join is for Bad Sports only.
|
||||
{ 20, "Cheaters Only" }, // The session you are trying to join is for cheaters only.
|
||||
{ 27, "Bad Reputation" }, // Unable to join this session, your account has a bad reputation.
|
||||
{ 28, "May Not Exist" }, // Unable to connect to session. The session may no longer exist.
|
||||
{ 29, "Premium Race" }, // Unable to Join. The session you are trying to join is a Premium Race. Joining and accepting invites is disabled for this mode.
|
||||
};
|
||||
}
|
28
src/core/data/infractions.hpp
Normal file
28
src/core/data/infractions.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "gta/joaat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
// Add new values to the bottom
|
||||
enum class Infraction
|
||||
{
|
||||
DESYNC_PROTECTION,
|
||||
BREAKUP_KICK_DETECTED,
|
||||
LOST_CONNECTION_KICK_DETECTED,
|
||||
SPOOFED_ROCKSTAR_ID,
|
||||
TRIGGERED_ANTICHEAT,
|
||||
TRIED_CRASH_PLAYER,
|
||||
TRIED_KICK_PLAYER
|
||||
};
|
||||
|
||||
inline std::unordered_map<Infraction, const char*> infraction_desc =
|
||||
{
|
||||
{Infraction::DESYNC_PROTECTION, "Used desync protections"},
|
||||
{Infraction::BREAKUP_KICK_DETECTED, "Kicked someone using breakup kick"},
|
||||
{Infraction::LOST_CONNECTION_KICK_DETECTED, "Tried to kick someone using lost connection kick"},
|
||||
{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"}
|
||||
};
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
#include "imgui.h"
|
||||
#include <bitset>
|
||||
|
||||
class CNetGamePlayer;
|
||||
|
||||
namespace big
|
||||
{
|
||||
class menu_settings;
|
||||
@ -195,6 +197,8 @@ namespace big
|
||||
bool log_text_messages = false;
|
||||
bool decloak_players = false;
|
||||
bool force_session_host = false;
|
||||
bool player_magnet_enabled = false;
|
||||
int player_magnet_count = 32;
|
||||
bool is_team = false;
|
||||
};
|
||||
|
||||
@ -401,6 +405,8 @@ namespace big
|
||||
int friend_count = 0;
|
||||
int player_count = 0;
|
||||
|
||||
CNetGamePlayer* m_syncing_player = nullptr;
|
||||
|
||||
debug debug{};
|
||||
tunables tunables{};
|
||||
notifications notifications{};
|
||||
@ -603,6 +609,8 @@ namespace big
|
||||
this->session.disable_chat_filter = j["session"]["disable_chat_filter"];
|
||||
this->session.decloak_players = j["session"]["decloak_players"];
|
||||
this->session.force_session_host = j["session"]["force_session_host"];
|
||||
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->settings.dev_dlc = j["settings"]["dev_dlc"];
|
||||
@ -921,6 +929,8 @@ namespace big
|
||||
{ "disable_chat_filter", this->session.disable_chat_filter },
|
||||
{ "decloak_players", this->session.decloak_players },
|
||||
{ "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 }
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,13 @@
|
||||
#pragma once
|
||||
#include "datanodes/player/CPlayerGameStateDataNode.hpp"
|
||||
#include "rage/rlGamerInfo.hpp"
|
||||
#include <datanodes/player/CPlayerGameStateDataNode.hpp>
|
||||
#include <datanodes/vehicle/CVehicleGadgetDataNode.hpp>
|
||||
|
||||
class CMsgJoinResponse;
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class netConnectionManager;
|
||||
}
|
||||
|
||||
namespace big::functions
|
||||
{
|
||||
@ -37,7 +44,7 @@ namespace big::functions
|
||||
using write_bitbuf_int64 = bool(*)(rage::datBitBuffer* buffer, int64_t val, int bits);
|
||||
using write_bitbuf_int32 = bool(*)(rage::datBitBuffer* buffer, int32_t val, int bits);
|
||||
using write_bitbuf_bool = bool(*)(rage::datBitBuffer* buffer, bool val, int bits);
|
||||
using write_bitbuf_array = bool(*)(rage::datBitBuffer* buffer, uint8_t* val, int bits, int unk);
|
||||
using write_bitbuf_array = bool(*)(rage::datBitBuffer* buffer, void* val, int bits, int unk);
|
||||
|
||||
// Bitbuffer read/write END
|
||||
// Received Event Signatures START
|
||||
@ -69,5 +76,13 @@ namespace big::functions
|
||||
|
||||
using generate_uuid = bool(*)(std::uint64_t* uuid);
|
||||
|
||||
using get_vehicle_gadget_array_size = int(*)(eVehicleGadgetType type);
|
||||
|
||||
using write_join_response_data = bool(*)(CMsgJoinResponse* response, void* data, int size, uint32_t* size_used);
|
||||
|
||||
using queue_packet = bool(*)(rage::netConnectionManager* mgr, int msg_id, void* data, int size, int flags, void* unk);
|
||||
|
||||
using generate_uuid = bool(*)(std::uint64_t* uuid);
|
||||
|
||||
using send_chat_message = bool(*)(int64_t* send_chat_ptr, rage::rlGamerInfo* game_info, char* message, bool is_team);
|
||||
}
|
||||
|
@ -2,205 +2,4 @@
|
||||
#include <cstdint>
|
||||
#include "fwddec.hpp"
|
||||
#include "sysMemAllocator.hpp"
|
||||
|
||||
namespace rage
|
||||
{
|
||||
#pragma pack(push, 8)
|
||||
template <typename T>
|
||||
class atArray
|
||||
{
|
||||
public:
|
||||
atArray()
|
||||
{
|
||||
m_data = nullptr;
|
||||
m_count = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
atArray(const atArray& right)
|
||||
{
|
||||
m_count = right.m_count;
|
||||
m_size = right.m_size;
|
||||
|
||||
m_data = (T*)rage::GetAllocator()->allocate(m_size * sizeof(T), 16, 0);
|
||||
std::uninitialized_copy(right.m_data, right.m_data + right.m_count, m_data);
|
||||
}
|
||||
|
||||
atArray(int capacity)
|
||||
{
|
||||
m_data = (T*)rage::GetAllocator()->allocate(capacity * sizeof(T), 16, 0);
|
||||
m_count = 0;
|
||||
m_size = capacity;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_count = 0;
|
||||
m_size = 0;
|
||||
|
||||
if (m_data)
|
||||
{
|
||||
rage::GetAllocator()->free(m_data);
|
||||
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void append(atArray<T> array_value)
|
||||
{
|
||||
auto value_array_size = array_value.size();
|
||||
auto old_capacity = m_count;
|
||||
|
||||
if ((value_array_size + m_count) > std::numeric_limits<uint16_t>::max())
|
||||
LOG(FATAL) << "RAGE atArray::append was given too large of an atArray to append";
|
||||
|
||||
auto size = (uint16_t)value_array_size;
|
||||
expand(m_count + size);
|
||||
m_size += size;
|
||||
|
||||
auto i = old_capacity;
|
||||
for (auto weapon_hash : array_value)
|
||||
{
|
||||
m_data[i] = weapon_hash;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void append(std::vector<T> value_array)
|
||||
{
|
||||
auto value_array_size = value_array.size();
|
||||
auto old_capacity = m_count;
|
||||
|
||||
if ((value_array_size + m_count) > std::numeric_limits<uint16_t>::max())
|
||||
LOG(FATAL) << "RAGE atArray::append was given too large of a vector to append";
|
||||
|
||||
auto size = (uint16_t)value_array_size;
|
||||
expand(m_count + size);
|
||||
m_size += size;
|
||||
|
||||
auto i = old_capacity;
|
||||
for (auto weapon_hash : value_array)
|
||||
{
|
||||
m_data[i] = weapon_hash;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void append(const std::initializer_list<T> value_array)
|
||||
{
|
||||
auto value_array_size = value_array.size();
|
||||
auto old_capacity = m_count;
|
||||
|
||||
if ((value_array_size + m_count) > std::numeric_limits<uint16_t>::max())
|
||||
LOG(FATAL) << "RAGE atArray::append was given too large of a list to append";
|
||||
|
||||
auto size = (uint16_t)value_array_size;
|
||||
expand(m_count + size);
|
||||
m_size += size;
|
||||
|
||||
auto i = old_capacity;
|
||||
for (const T* it = value_array.begin(); it != value_array.end(); ++it)
|
||||
{
|
||||
m_data[i] = *it;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void append(T value)
|
||||
{
|
||||
set(m_count, value);
|
||||
}
|
||||
|
||||
void set(uint16_t offset, const T& value)
|
||||
{
|
||||
if (offset >= m_count)
|
||||
{
|
||||
expand(offset + 1);
|
||||
}
|
||||
|
||||
if (offset >= m_size)
|
||||
{
|
||||
m_size = offset + 1;
|
||||
}
|
||||
|
||||
m_data[offset] = value;
|
||||
}
|
||||
|
||||
void expand(uint16_t newSize)
|
||||
{
|
||||
if (m_count >= newSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
T* newOffset = (T*)rage::GetAllocator()->allocate(newSize * sizeof(T), 16, 0);
|
||||
|
||||
// initialize the new entries
|
||||
std::uninitialized_fill(newOffset, newOffset + newSize, T());
|
||||
|
||||
// copy the existing entries
|
||||
if (m_data)
|
||||
{
|
||||
std::copy(m_data, m_data + m_size, newOffset);
|
||||
|
||||
rage::GetAllocator()->free(m_data);
|
||||
}
|
||||
|
||||
m_data = newOffset;
|
||||
m_count = newSize;
|
||||
}
|
||||
|
||||
T* begin() const
|
||||
{
|
||||
return &m_data[0];
|
||||
}
|
||||
|
||||
T* end() const
|
||||
{
|
||||
return &m_data[m_size];
|
||||
}
|
||||
|
||||
T* data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
std::uint16_t size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
std::uint16_t count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
T& operator[](std::uint16_t index) const
|
||||
{
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& o, const atArray<T>& j)
|
||||
{
|
||||
o << "Array Size: " << j.size() << std::endl;
|
||||
for(int i = 0; i < j.size(); i++)
|
||||
{
|
||||
T item = j[i];
|
||||
if (std::is_pointer<T>())
|
||||
o << "\tArray Pointer: " << HEX_TO_UPPER(item) << " Item: [" << HEX_TO_UPPER(*(T*)item) << "]";
|
||||
else
|
||||
o << "\tArray Item: " << item;
|
||||
if (i != j.size() - 1)
|
||||
o << std::endl;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_data;
|
||||
std::uint16_t m_size;
|
||||
std::uint16_t m_count;
|
||||
};
|
||||
static_assert(sizeof(rage::atArray<Hash>) == 0x10, "rage::atArray is not properly sized");
|
||||
#pragma pack(pop)
|
||||
}
|
||||
#include <rage/atArray.hpp>
|
@ -3,38 +3,6 @@
|
||||
|
||||
constexpr auto MAX_PLAYERS = 32;
|
||||
|
||||
enum eObjType : uint16_t {
|
||||
carObjType = 0,
|
||||
bikeObjType = 1,
|
||||
boatObjType = 2,
|
||||
doorObjType = 3,
|
||||
heliObjType = 4,
|
||||
objType = 5,
|
||||
pedObjType = 6,
|
||||
pickupObjType = 7,
|
||||
pickupPlacementObjType = 8,
|
||||
planeObjType = 9,
|
||||
submarineObjType = 10,
|
||||
playerObjType = 11,
|
||||
trailerObjType = 12,
|
||||
trainObjType = 13,
|
||||
unkObjType14 = 14,
|
||||
unkObjType = 69
|
||||
};
|
||||
|
||||
enum eSyncReply : int64_t
|
||||
{
|
||||
NoSyncTreeFound = 1, // No sync tree found
|
||||
PlayerIsNotInOurRoamingBubble = 1, // Player is not in our roaming bubble
|
||||
WrongOwner = 2, // Wrong owner
|
||||
ObjectIsBeingReassinged = 2, // Object is being reassigned
|
||||
CantApplyData_NoNetworkObject = 4, // Can't apply data - no network object
|
||||
CantApplyData = 6, // Can't apply data
|
||||
CantApplyData_NoGameObject = 6, // Can't apply data - no game object
|
||||
CantApplyData_NetworkClosed = 7, // Can't apply data - network closed
|
||||
SuccessfullSync = 8
|
||||
};
|
||||
|
||||
enum class ControllerInputs : std::uint32_t
|
||||
{
|
||||
INPUT_NEXT_CAMERA,
|
||||
|
@ -6,12 +6,48 @@
|
||||
#pragma pack(push, 1)
|
||||
namespace rage
|
||||
{
|
||||
class CSyncDataBase
|
||||
{
|
||||
public:
|
||||
virtual ~CSyncDataBase() = default;
|
||||
virtual bool SerializeDword(uint32_t* dword, int size) = 0;
|
||||
virtual bool SerializeWord(uint16_t* word, int size) = 0;
|
||||
virtual bool SerializeByte(uint8_t* byte, int size) = 0;
|
||||
virtual bool SerializeInt32(int32_t* i, int size) = 0;
|
||||
virtual bool SerializeInt16(int16_t* i, int size) = 0;
|
||||
virtual bool SerializeSignedByte(int8_t* byte, int size) = 0;
|
||||
virtual bool SerializeBool(bool* flag) = 0;
|
||||
virtual bool SerializeInt64(int64_t* i, int size) = 0;
|
||||
virtual bool SerializeInt32Alt(int32_t* i, int size) = 0;
|
||||
virtual bool SerializeInt16Alt(int16_t* i, int size) = 0;
|
||||
virtual bool SerializeSignedByteAlt(int8_t* byte, int size) = 0;
|
||||
virtual bool SerializeQword(uint64_t* qword, int size) = 0;
|
||||
virtual bool SerializeDwordAlt(uint32_t* dword, int size) = 0;
|
||||
virtual bool SerializeWordAlt(uint16_t* word, int size) = 0;
|
||||
virtual bool SerializeByteAlt(uint8_t* byte, int size) = 0;
|
||||
virtual bool SerializeSignedFloat(float* flt, float divisor, int size) = 0;
|
||||
virtual bool SerializeFloat(float* flt, float divisor, int size) = 0;
|
||||
virtual bool SerializeNetworkId(uint16_t* net_id) = 0;
|
||||
virtual bool SerializeVector3(rage::fvector3* vec3, float divisor, int size) = 0;
|
||||
virtual bool SerializeQuaternion(void* unk) = 0; // i have no clue what that is
|
||||
virtual bool SerializeVector3SignedZComponent(rage::fvector3* vec3, float divisor, int size) = 0;
|
||||
virtual bool SerializeOrientation(rage::fvector4* vec4, float size) = 0; // yes, the size is a float
|
||||
virtual bool SerializeArray(void* array, int size) = 0;
|
||||
virtual bool SerializeString(char* str, int max_length) = 0;
|
||||
virtual bool IsSizeCalculator() = 0;
|
||||
virtual bool IsSizeCalculator2() = 0;
|
||||
|
||||
void* unk_0x8;
|
||||
void* syncLog;
|
||||
datBitBuffer* buffer;
|
||||
};
|
||||
|
||||
class netPlayer;
|
||||
|
||||
class datBitBuffer
|
||||
{
|
||||
public:
|
||||
datBitBuffer(uint8_t* data, uint32_t size) {
|
||||
datBitBuffer(void* data, uint32_t size) {
|
||||
m_data = data;
|
||||
m_bitOffset = 0;
|
||||
m_maxBit = size * 8;
|
||||
@ -46,7 +82,7 @@ namespace rage
|
||||
return 0;
|
||||
auto const bufPos = m_bitsRead + m_bitOffset;
|
||||
auto const initialBitOffset = bufPos & 0b111;
|
||||
auto const start = &m_data[bufPos / 8];
|
||||
auto const start = &((uint8_t*)m_data)[bufPos / 8];
|
||||
auto const next = &start[1];
|
||||
auto result = (start[0] << initialBitOffset) & 0xff;
|
||||
for (auto i = 0; i < ((numBits - 1) / 8); i++) {
|
||||
@ -139,7 +175,7 @@ namespace rage
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool WriteArray(uint8_t* array, int size) {
|
||||
bool WriteArray(void* array, int size) {
|
||||
return big::g_pointers->m_write_bitbuf_array(this, array, size, 0);
|
||||
}
|
||||
bool ReadArray(PVOID array, int size) {
|
||||
@ -167,8 +203,16 @@ namespace rage
|
||||
|
||||
return T(val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void Write(T data, int length)
|
||||
{
|
||||
static_assert(sizeof(T) <= 8, "maximum of 64 bit write");
|
||||
|
||||
WriteQWord((uint64_t)data, length);
|
||||
}
|
||||
public:
|
||||
uint8_t* m_data; //0x0000
|
||||
void* m_data; //0x0000
|
||||
uint32_t m_bitOffset; //0x0008
|
||||
uint32_t m_maxBit; //0x000C
|
||||
uint32_t m_bitsRead; //0x0010
|
||||
|
@ -1,72 +1,3 @@
|
||||
#pragma once
|
||||
#include "fwddec.hpp"
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class sysMemAllocator
|
||||
{
|
||||
public:
|
||||
virtual ~sysMemAllocator() = 0;
|
||||
|
||||
virtual void SetQuitOnFail(bool) = 0;
|
||||
virtual void* Allocate(size_t size, size_t align, int subAllocator) = 0;
|
||||
|
||||
inline void* allocate(size_t size, size_t align, int subAllocator)
|
||||
{
|
||||
return Allocate(size, align, subAllocator);
|
||||
}
|
||||
|
||||
virtual void* TryAllocate(size_t size, size_t align, int subAllocator) = 0;
|
||||
|
||||
virtual void Free(void* pointer) = 0;
|
||||
|
||||
virtual void free(void* pointer)
|
||||
{
|
||||
return Free(pointer);
|
||||
}
|
||||
|
||||
virtual void TryFree(void* pointer) = 0;
|
||||
|
||||
virtual void Resize(void* pointer, size_t size) = 0;
|
||||
|
||||
virtual sysMemAllocator* GetAllocator(int allocator) const = 0;
|
||||
|
||||
virtual sysMemAllocator* GetAllocator(int allocator) = 0;
|
||||
|
||||
virtual sysMemAllocator* GetPointerOwner(void* pointer) = 0;
|
||||
|
||||
virtual size_t GetSize(void* pointer) const = 0;
|
||||
|
||||
virtual size_t GetMemoryUsed(int memoryBucket) = 0;
|
||||
|
||||
virtual size_t GetMemoryAvailable() = 0;
|
||||
|
||||
public:
|
||||
|
||||
static sysMemAllocator* UpdateAllocatorValue()
|
||||
{
|
||||
//B9 ? ? ? ? 48 8B 0C 01 45 33 C9 49 8B D2 48
|
||||
auto g_gtaTlsEntry = *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8); //This has been 0xC8 since 323, I'm not adding this signature to pointers...
|
||||
|
||||
if (g_gtaTlsEntry == nullptr)
|
||||
LOG(FATAL) << "Failed to find tlsEntry within GTA5.exe via __readgsqword";
|
||||
|
||||
*(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8) = g_gtaTlsEntry;
|
||||
*(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8 - 8) = g_gtaTlsEntry;
|
||||
|
||||
return g_gtaTlsEntry;
|
||||
}
|
||||
};
|
||||
|
||||
inline sysMemAllocator* GetAllocator()
|
||||
{
|
||||
sysMemAllocator* allocator = *(sysMemAllocator**)(*(uintptr_t*)(__readgsqword(88)) + 0xC8);
|
||||
|
||||
if (!allocator)
|
||||
{
|
||||
return sysMemAllocator::UpdateAllocatorValue();
|
||||
}
|
||||
|
||||
return allocator;
|
||||
}
|
||||
}
|
||||
#include <rage/sysMemAllocator.hpp>
|
@ -37,7 +37,7 @@ namespace big
|
||||
colors[ImGuiCol_Text] = ImVec4(0.80f, 0.80f, 0.83f, 1.00f);
|
||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f);
|
||||
colors[ImGuiCol_WindowBg] = ImGui::ColorConvertU32ToFloat4(g->window.color);
|
||||
colors[ImGuiCol_ChildBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);
|
||||
colors[ImGuiCol_ChildBg] = ImGui::ColorConvertU32ToFloat4(g->window.color);
|
||||
colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);
|
||||
colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f);
|
||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f);
|
||||
|
@ -53,7 +53,10 @@ namespace big
|
||||
detour_hook_helper::add<hooks::assign_physical_index>("API", g_pointers->m_assign_physical_index);
|
||||
|
||||
detour_hook_helper::add<hooks::receive_net_message>("RNM", g_pointers->m_receive_net_message);
|
||||
|
||||
detour_hook_helper::add<hooks::received_clone_create>("RCC", g_pointers->m_received_clone_create);
|
||||
detour_hook_helper::add<hooks::received_clone_sync>("RCS", g_pointers->m_received_clone_sync);
|
||||
detour_hook_helper::add<hooks::can_apply_data>("CAD", g_pointers->m_can_apply_data);
|
||||
|
||||
detour_hook_helper::add<hooks::get_network_event_data>("GNED", g_pointers->m_get_network_event_data);
|
||||
detour_hook_helper::add<hooks::write_player_gamer_data_node>("WPGDN", g_pointers->m_write_player_gamer_data_node);
|
||||
@ -65,6 +68,14 @@ namespace big
|
||||
detour_hook_helper::add<hooks::update_presence_attribute_int>("UPAI", g_pointers->m_update_presence_attribute_int);
|
||||
detour_hook_helper::add<hooks::update_presence_attribute_string>("UPAS", g_pointers->m_update_presence_attribute_string);
|
||||
|
||||
detour_hook_helper::add<hooks::serialize_dynamic_entity_game_state_data_node>("SDEGSDN", g_pointers->m_serialize_dynamic_entity_game_state_data_node);
|
||||
detour_hook_helper::add<hooks::serialize_ped_inventory_data_node>("SPIDN", g_pointers->m_serialize_ped_inventory_data_node);
|
||||
detour_hook_helper::add<hooks::serialize_vehicle_gadget_data_node>("SVGDN", g_pointers->m_serialize_vehicle_gadget_data_node);
|
||||
|
||||
detour_hook_helper::add<hooks::handle_join_request>("HJR", g_pointers->m_handle_join_request);
|
||||
|
||||
detour_hook_helper::add<hooks::sort_session_details>("SSD", g_pointers->m_sort_session_details);
|
||||
|
||||
g_hooking = this;
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,20 @@
|
||||
#include "vmt_hook.hpp"
|
||||
#include "MinHook.h"
|
||||
#include "gta/enums.hpp"
|
||||
#include "datanodes/player/CPlayerGamerDataNode.hpp"
|
||||
#include "datanodes/player/CPlayerGameStateDataNode.hpp"
|
||||
#include "rage/rlMetric.hpp"
|
||||
|
||||
class CPlayerGamerDataNode;
|
||||
class CPlayerGameStateDataNode;
|
||||
class CPedInventoryDataNode;
|
||||
class CDynamicEntityGameStateDataNode;
|
||||
class CVehicleGadgetDataNode;
|
||||
class CJoinRequestContext;
|
||||
class SessionSortEntry;
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class rlMetric;
|
||||
class snSession;
|
||||
}
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -61,7 +72,9 @@ namespace big
|
||||
static void format_metric_for_sending(int a1, int64_t a2, int64_t a3, rage::rlMetric* metric);
|
||||
|
||||
//SYNC
|
||||
static int64_t received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eObjType sync_type, uint16_t obj_id, rage::datBitBuffer* bufer, uint16_t unk, uint32_t timestamp);
|
||||
static bool received_clone_create(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, int32_t object_id, int32_t object_flag, rage::datBitBuffer* buffer, int32_t timestamp);
|
||||
static eAckCode received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, uint16_t object_id, rage::datBitBuffer* bufer, uint16_t unk, uint32_t timestamp);
|
||||
static bool can_apply_data(rage::netSyncTree* tree, rage::netObject* object);
|
||||
|
||||
static void write_player_gamer_data_node(rage::netObject* player, CPlayerGamerDataNode* node);
|
||||
static bool write_player_game_state_data_node(rage::netObject* player, CPlayerGameStateDataNode* node);
|
||||
@ -70,6 +83,14 @@ namespace big
|
||||
|
||||
static bool update_presence_attribute_int(void* presence_data, int profile_index, char* attr, std::uint64_t value);
|
||||
static bool update_presence_attribute_string(void* presence_data, int profile_index, char* attr, char* value);
|
||||
|
||||
static void serialize_ped_inventory_data_node(CPedInventoryDataNode* node, rage::CSyncDataBase* data);
|
||||
static void serialize_dynamic_entity_game_state_data_node(CDynamicEntityGameStateDataNode* node, rage::CSyncDataBase* data);
|
||||
static void serialize_vehicle_gadget_data_node(CVehicleGadgetDataNode* node, rage::CSyncDataBase* data);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
class minhook_keepalive
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "hooking.hpp"
|
||||
#include <rage/rlMetric.hpp>
|
||||
|
||||
namespace rage
|
||||
{
|
||||
|
19
src/hooks/misc/sort_session_details.cpp
Normal file
19
src/hooks/misc/sort_session_details.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "hooking.hpp"
|
||||
#include <network/Network.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
// true => e1 > e2
|
||||
// false => e1 < e2
|
||||
bool hooks::sort_session_details(SessionSortEntry* e1, SessionSortEntry* e2)
|
||||
{
|
||||
if (g->session.player_magnet_enabled)
|
||||
{
|
||||
return std::abs((int)e1->m_session_detail->m_player_count - g->session.player_magnet_count) < std::abs((int)e2->m_session_detail->m_player_count - g->session.player_magnet_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
return g_hooking->get_original<hooks::sort_session_details>()(e1, e2);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
#include "hooking.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "packet.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include <network/Network.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -40,6 +45,35 @@ namespace big
|
||||
|
||||
if (g->notifications.player_join.notify)
|
||||
g_notification_service->push("Player Joined", std::format("{} taking slot #{} with Rockstar ID: {}", net_player_data->m_name, player->m_player_id, net_player_data->m_gamer_handle_2.m_rockstar_id));
|
||||
|
||||
auto id = player->m_player_id;
|
||||
g_fiber_pool->queue_job([id]
|
||||
{
|
||||
if (auto plyr = g_player_service->get_by_id(id))
|
||||
{
|
||||
if (auto entry = g_player_database_service->get_player_by_rockstar_id(plyr->get_net_data()->m_gamer_handle_2.m_rockstar_id))
|
||||
{
|
||||
plyr->is_modder = entry->is_modder;
|
||||
plyr->block_join = entry->block_join;
|
||||
plyr->block_join_reason = plyr->block_join_reason;
|
||||
|
||||
if (strcmp(plyr->get_name(), entry->name.data()))
|
||||
{
|
||||
g_notification_service->push("Players", std::format("{} changed their name to {}", entry->name, plyr->get_name()));
|
||||
entry->name = plyr->get_name();
|
||||
g_player_database_service->save();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto snplyr = plyr->get_session_player())
|
||||
{
|
||||
packet msg{};
|
||||
msg.write_message(rage::eNetMessage::MsgSessionEstablishedRequest);
|
||||
msg.write<uint64_t>(gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id, 64);
|
||||
msg.send(snplyr->m_msg_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
287
src/hooks/protections/can_apply_data.cpp
Normal file
287
src/hooks/protections/can_apply_data.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
#include "hooking.hpp"
|
||||
#include "core/globals.hpp"
|
||||
#include "base/CObject.hpp"
|
||||
#include "entities/fwEntity.hpp"
|
||||
#include "rage/netSyncDataNodeBase.hpp"
|
||||
#include "rage/netSyncTree.hpp"
|
||||
#include "gta/net_object_mgr.hpp"
|
||||
#include "datanodes/door/CDoorCreationDataNode.hpp"
|
||||
#include "datanodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp"
|
||||
#include "datanodes/object/CObjectCreationDataNode.hpp"
|
||||
#include "datanodes/ped/CPedAttachDataNode.hpp"
|
||||
#include "datanodes/ped/CPedCreationDataNode.hpp"
|
||||
#include "datanodes/ped/CPedInventoryDataNode.hpp"
|
||||
#include "datanodes/pickup/CPickupCreationDataNode.hpp"
|
||||
#include "datanodes/physical/CPhysicalAttachDataNode.hpp"
|
||||
#include "datanodes/player/CPlayerAppearanceDataNode.hpp"
|
||||
#include "datanodes/proximity_migrateable/CSectorDataNode.hpp"
|
||||
#include "datanodes/vehicle/CVehicleCreationDataNode.hpp"
|
||||
#include "datanodes/vehicle/CVehicleGadgetDataNode.hpp"
|
||||
#include "network/netObject.hpp"
|
||||
#include "base/CBaseModelInfo.hpp"
|
||||
#include "vehicle/CVehicleModelInfo.hpp"
|
||||
#include "util/model_info.hpp"
|
||||
#include "network/CNetGamePlayer.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#define CLASS_TO_MANGLED_NAME(c) "?AV"#c"@@"
|
||||
|
||||
namespace big
|
||||
{
|
||||
constexpr uint64_t operator ""_fnv1a(char const* str, std::size_t len)
|
||||
{
|
||||
auto const fnv_offset_basis = 14695981039346656037ULL;
|
||||
auto const fnv_prime = 1099511628211ULL;
|
||||
|
||||
auto value = fnv_offset_basis;
|
||||
for (auto i = 0; i < len; i++)
|
||||
{
|
||||
value ^= static_cast<size_t>(str[i]);
|
||||
value *= fnv_prime;
|
||||
}
|
||||
value ^= value >> 32;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr uint32_t crash_peds[] = { RAGE_JOAAT("slod_human"), RAGE_JOAAT("slod_small_quadped"), RAGE_JOAAT("slod_large_quadped") };
|
||||
|
||||
constexpr uint32_t crash_vehicles[] = { RAGE_JOAAT("arbitergt"), RAGE_JOAAT("astron2"), RAGE_JOAAT("cyclone2"), RAGE_JOAAT("ignus2"), RAGE_JOAAT("s95") };
|
||||
|
||||
constexpr uint32_t crash_objects[] = { RAGE_JOAAT("prop_dummy_01"), RAGE_JOAAT("prop_dummy_car"), RAGE_JOAAT("prop_dummy_light"), RAGE_JOAAT("prop_dummy_plane"),
|
||||
RAGE_JOAAT("prop_distantcar_night"), RAGE_JOAAT("prop_distantcar_day"), RAGE_JOAAT("hei_bh1_08_details4_em_night"),
|
||||
RAGE_JOAAT("dt1_18_sq_night_slod"), RAGE_JOAAT("ss1_12_night_slod"), -1288391198, RAGE_JOAAT("h4_prop_bush_bgnvla_med_01"), RAGE_JOAAT("h4_prop_bush_bgnvla_lrg_01"),
|
||||
RAGE_JOAAT("h4_prop_bush_buddleia_low_01"), RAGE_JOAAT("h4_prop_bush_ear_aa"), RAGE_JOAAT("h4_prop_bush_ear_ab"), RAGE_JOAAT("h4_prop_bush_fern_low_01"),
|
||||
RAGE_JOAAT("h4_prop_bush_fern_tall_cc"), RAGE_JOAAT("h4_prop_bush_mang_ad"), RAGE_JOAAT("h4_prop_bush_mang_low_aa"), RAGE_JOAAT("h4_prop_bush_mang_low_ab"),
|
||||
RAGE_JOAAT("h4_prop_bush_seagrape_low_01"), RAGE_JOAAT("prop_h4_ground_cover"), RAGE_JOAAT("h4_prop_weed_groundcover_01"), RAGE_JOAAT("h4_prop_grass_med_01"),
|
||||
RAGE_JOAAT("h4_prop_grass_tropical_lush_01"), RAGE_JOAAT("h4_prop_grass_wiregrass_01"), RAGE_JOAAT("h4_prop_weed_01_plant"), RAGE_JOAAT("h4_prop_weed_01_row"),
|
||||
RAGE_JOAAT("urbanweeds02_l1"), RAGE_JOAAT("proc_forest_grass01"), RAGE_JOAAT("prop_small_bushyba"), RAGE_JOAAT("v_res_d_dildo_a"), RAGE_JOAAT("v_res_d_dildo_b"), RAGE_JOAAT("v_res_d_dildo_c"),
|
||||
RAGE_JOAAT("v_res_d_dildo_d"), RAGE_JOAAT("v_res_d_dildo_e"), RAGE_JOAAT("v_res_d_dildo_f"), RAGE_JOAAT("v_res_skateboard"), RAGE_JOAAT("prop_battery_01"), RAGE_JOAAT("prop_barbell_01"),
|
||||
RAGE_JOAAT("prop_barbell_02"), RAGE_JOAAT("prop_bandsaw_01"), RAGE_JOAAT("prop_bbq_3"), RAGE_JOAAT("v_med_curtainsnewcloth2"), RAGE_JOAAT("bh1_07_flagpoles"),
|
||||
92962485 };
|
||||
|
||||
inline bool is_crash_ped(uint32_t model)
|
||||
{
|
||||
for (auto iterator : crash_peds)
|
||||
if (iterator == model)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_crash_vehicle(uint32_t model)
|
||||
{
|
||||
for (auto iterator : crash_vehicles)
|
||||
if (iterator == model)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_crash_object(uint32_t model)
|
||||
{
|
||||
for (auto iterator : crash_objects)
|
||||
if (iterator == model)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get_node_from_object(rage::netSyncNodeBase* node)
|
||||
{
|
||||
constexpr uint64_t hash = CLASS_TO_MANGLED_NAME(T)""_fnv1a;
|
||||
if (node->IsParentNode())
|
||||
{
|
||||
for (auto child = node->m_first_child; child; child = child->m_next_sibling)
|
||||
{
|
||||
T* attach_node = get_node_from_object<T>(child);
|
||||
if (attach_node != nullptr)
|
||||
return attach_node;
|
||||
}
|
||||
}
|
||||
else if (node->IsDataNode())
|
||||
{
|
||||
if (typeid(*node).hash_code() == hash)
|
||||
return dynamic_cast<T*>(node);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool is_attachment_infinite(CPhysicalAttachDataNode* node, uint16_t object_id)
|
||||
{
|
||||
if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object)
|
||||
{
|
||||
if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree)
|
||||
{
|
||||
if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node)
|
||||
{
|
||||
const auto attached_attach_node = get_node_from_object<CPhysicalAttachDataNode>(base_node);
|
||||
if (attached_attach_node && attached_attach_node->m_attached)
|
||||
{
|
||||
if (attached_attach_node->m_attached_to == object_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return is_attachment_infinite(attached_attach_node, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_ped_attachment_infinite(CPedAttachDataNode* node, uint16_t object_id)
|
||||
{
|
||||
if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object)
|
||||
{
|
||||
if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree)
|
||||
{
|
||||
if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node)
|
||||
{
|
||||
const auto attached_attach_node = get_node_from_object<CPedAttachDataNode>(base_node);
|
||||
if (attached_attach_node && attached_attach_node->m_attached)
|
||||
{
|
||||
if (attached_attach_node->m_attached_to == object_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return is_ped_attachment_infinite(attached_attach_node, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_node(rage::netSyncNodeBase* node, CNetGamePlayer* sender, rage::netObject* object)
|
||||
{
|
||||
if (node->IsParentNode())
|
||||
{
|
||||
for (auto child = node->m_first_child; child; child = child->m_next_sibling)
|
||||
{
|
||||
if (check_node(child, sender, object))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (node->IsDataNode())
|
||||
{
|
||||
switch (typeid(*node).hash_code())
|
||||
{
|
||||
case "?AVCDoorCreationDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CDoorCreationDataNode*>(node);
|
||||
if (is_crash_object(creation_node->m_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid door model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPickupCreationDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CPickupCreationDataNode*>(node);
|
||||
if (is_crash_object(creation_node->m_custom_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid door model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPhysicalAttachDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto attach_node = dynamic_cast<CPhysicalAttachDataNode*>(node);
|
||||
|
||||
// TODO: Find a better method to avoid false positives
|
||||
auto model_hash = object->GetGameObject() ? object->GetGameObject()->m_model_info->m_hash : 0;
|
||||
if (attach_node->m_attached && attach_node->m_attached_to == object->m_object_id && (model_hash != RAGE_JOAAT("hauler2") && model_hash != RAGE_JOAAT("phantom3")))
|
||||
{
|
||||
notify::crash_blocked(sender, "infinite physical attachment");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPedCreationDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CPedCreationDataNode*>(node);
|
||||
if (is_crash_ped(creation_node->m_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid ped model");
|
||||
return true;
|
||||
}
|
||||
else if (creation_node->m_has_prop && is_crash_object(creation_node->m_prop_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid ped prop model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPedAttachDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto attach_node = dynamic_cast<CPedAttachDataNode*>(node);
|
||||
if (attach_node->m_attached && attach_node->m_attached_to == object->m_object_id)
|
||||
{
|
||||
notify::crash_blocked(sender, "infinite ped attachment");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCVehicleCreationDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto vehicle_creation_node = dynamic_cast<CVehicleCreationDataNode*>(node);
|
||||
if (is_crash_vehicle(vehicle_creation_node->m_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid vehicle model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCObjectCreationDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CObjectCreationDataNode*>(node);
|
||||
if (is_crash_object(creation_node->m_model))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid object model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPlayerAppearanceDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto player_appearance_node = dynamic_cast<CPlayerAppearanceDataNode*>(node);
|
||||
if (is_crash_ped(player_appearance_node->m_model_hash))
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid player model");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCSectorDataNode@@"_fnv1a:
|
||||
{
|
||||
const auto sector_node = dynamic_cast<CSectorDataNode*>(node);
|
||||
if (sector_node->m_pos_x == 712 || sector_node->m_pos_y == 712 || sector_node->m_pos_z == 712)
|
||||
{
|
||||
notify::crash_blocked(sender, "invalid sector position");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hooks::can_apply_data(rage::netSyncTree* tree, rage::netObject* object)
|
||||
{
|
||||
if (tree->m_child_node_count && check_node(tree->m_sync_node, g->m_syncing_player, object))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_hooking->get_original<hooks::can_apply_data>()(tree, object);
|
||||
}
|
||||
}
|
24
src/hooks/protections/handle_join_request.cpp
Normal file
24
src/hooks/protections/handle_join_request.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "hooking.hpp"
|
||||
#include <network/snSession.hpp>
|
||||
#include <network/CMsgJoinResponse.hpp>
|
||||
#include <network/CJoinRequestContext.hpp>
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::handle_join_request(Network* network, rage::snSession* session, rage::rlGamerInfo* player_info, CJoinRequestContext* ctx, BOOL is_transition_session)
|
||||
{
|
||||
if (auto player = g_player_database_service->get_player_by_rockstar_id(player_info->m_gamer_handle_2.m_rockstar_id); player && player->block_join)
|
||||
{
|
||||
CMsgJoinResponse response{};
|
||||
response.m_status_code = player->block_join_reason;
|
||||
g_pointers->m_write_join_response_data(&response, ctx->m_join_response_data, 512, &ctx->m_join_response_size);
|
||||
g_notification_service->push("Block Join", std::format("Blocked {} from joining", player->name));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return g_hooking->get_original<hooks::handle_join_request>()(network, session, player_info, ctx, is_transition_session);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include <network/Network.hpp>
|
||||
|
||||
namespace big
|
||||
@ -86,6 +87,7 @@ namespace big
|
||||
{
|
||||
if (player->m_num_failed_transition_attempts++ == 20)
|
||||
{
|
||||
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;
|
||||
@ -120,6 +122,7 @@ namespace big
|
||||
if (player && pl && player->id() != pl->id() && count == 1 && frame->m_msg_id == -1)
|
||||
{
|
||||
g_notification_service->push_error("Warning!", std::format("{} breakup kicked {}!", player->get_name(), pl->get_name()));
|
||||
session::add_infraction(player, Infraction::BREAKUP_KICK_DETECTED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -133,6 +136,7 @@ namespace big
|
||||
auto self = g_player_service->get_self();
|
||||
if (self->get_net_data() && self->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
||||
{
|
||||
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
||||
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick you!", player->get_name()));
|
||||
return true;
|
||||
}
|
||||
@ -141,6 +145,7 @@ namespace big
|
||||
{
|
||||
if (plyr->get_net_data() && plyr != player && player->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
||||
{
|
||||
session::add_infraction(player, Infraction::LOST_CONNECTION_KICK_DETECTED);
|
||||
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick {}!", player->get_name(), plyr->get_name()));
|
||||
return true;
|
||||
}
|
||||
@ -148,6 +153,47 @@ namespace big
|
||||
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgSessionEstablished:
|
||||
{
|
||||
rage::rlGamerHandle handle{ 0 };
|
||||
if (player && player->get_net_data())
|
||||
{
|
||||
uint64_t session_id;
|
||||
buffer.ReadQWord(&session_id, 64);
|
||||
gamer_handle_deserialize(handle, buffer);
|
||||
if (session_id == gta_util::get_network()->m_game_session_ptr->m_rline_session.m_session_id)
|
||||
{
|
||||
if (handle.m_rockstar_id != player->get_net_data()->m_gamer_handle_2.m_rockstar_id)
|
||||
{
|
||||
session::add_infraction(player, Infraction::SPOOFED_ROCKSTAR_ID); // TODO: store this RID
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgNetComplaint:
|
||||
{
|
||||
uint64_t host_token{};
|
||||
buffer.ReadQWord(&host_token, 64);
|
||||
|
||||
std::vector<CNetGamePlayer*> players;
|
||||
|
||||
uint32_t num_of_tokens{};
|
||||
buffer.ReadDword(&num_of_tokens, 32);
|
||||
|
||||
if (player && host_token != player->get_net_data()->m_host_token)
|
||||
session::add_infraction(player, Infraction::DESYNC_PROTECTION);
|
||||
|
||||
return true; // block desync kicks as host
|
||||
}
|
||||
case rage::eNetMessage::MsgRequestObjectIds:
|
||||
{
|
||||
if (player && player->block_join)
|
||||
{
|
||||
g_notification_service->push("Join Blocker", std::format("Trying to prevent {} from joining...", player->get_name()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
src/hooks/protections/received_clone_create.cpp
Normal file
17
src/hooks/protections/received_clone_create.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "hooking.hpp"
|
||||
#include "util/notify.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::received_clone_create(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, int32_t object_id, int32_t object_flag, rage::datBitBuffer* buffer, int32_t timestamp)
|
||||
{
|
||||
if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN)
|
||||
{
|
||||
notify::crash_blocked(src, "out of bounds object type");
|
||||
return true;
|
||||
}
|
||||
|
||||
g->m_syncing_player = src;
|
||||
return g_hooking->get_original<hooks::received_clone_create>()(mgr, src, dst, object_type, object_id, object_flag, buffer, timestamp);
|
||||
}
|
||||
}
|
@ -1,406 +1,23 @@
|
||||
#include "hooking.hpp"
|
||||
#include "core/globals.hpp"
|
||||
#include "base/CObject.hpp"
|
||||
#include "entities/fwEntity.hpp"
|
||||
#include "rage/netSyncDataNodeBase.hpp"
|
||||
#include "rage/netSyncTree.hpp"
|
||||
#include "gta/net_object_mgr.hpp"
|
||||
#include "datanodes/door/CDoorCreationDataNode.hpp"
|
||||
#include "datanodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp"
|
||||
#include "datanodes/object/CObjectCreationDataNode.hpp"
|
||||
#include "datanodes/ped/CPedAttachDataNode.hpp"
|
||||
#include "datanodes/ped/CPedCreationDataNode.hpp"
|
||||
#include "datanodes/ped/CPedInventoryDataNode.hpp"
|
||||
#include "datanodes/pickup/CPickupCreationDataNode.hpp"
|
||||
#include "datanodes/physical/CPhysicalAttachDataNode.hpp"
|
||||
#include "datanodes/player/CPlayerAppearanceDataNode.hpp"
|
||||
#include "datanodes/proximity_migrateable/CSectorDataNode.hpp"
|
||||
#include "datanodes/vehicle/CVehicleCreationDataNode.hpp"
|
||||
#include "datanodes/vehicle/CVehicleGadgetDataNode.hpp"
|
||||
#include "network/netObject.hpp"
|
||||
#include "base/CBaseModelInfo.hpp"
|
||||
#include "vehicle/CVehicleModelInfo.hpp"
|
||||
#include "util/model_info.hpp"
|
||||
#include "network/CNetGamePlayer.hpp"
|
||||
#define CLASS_TO_MANGLED_NAME(c) "?AV"#c"@@"
|
||||
#include "util/notify.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
constexpr uint64_t operator ""_fnv1a(char const* str, std::size_t len)
|
||||
eAckCode hooks::received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eNetObjType object_type, uint16_t object_id, rage::datBitBuffer* buffer, uint16_t unk, uint32_t timestamp)
|
||||
{
|
||||
auto const fnv_offset_basis = 14695981039346656037ULL;
|
||||
auto const fnv_prime = 1099511628211ULL;
|
||||
|
||||
auto value = fnv_offset_basis;
|
||||
for (auto i = 0; i < len; i++) {
|
||||
value ^= static_cast<size_t>(str[i]);
|
||||
value *= fnv_prime;
|
||||
}
|
||||
value ^= value >> 32;
|
||||
|
||||
return value;
|
||||
if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN)
|
||||
{
|
||||
notify::crash_blocked(src, "out of bounds object type");
|
||||
return eAckCode::ACKCODE_FAIL;
|
||||
}
|
||||
|
||||
constexpr uint32_t crash_models[] = { RAGE_JOAAT("prop_dummy_01"), RAGE_JOAAT("prop_dummy_car"), RAGE_JOAAT("prop_dummy_light"), RAGE_JOAAT("prop_dummy_plane"), RAGE_JOAAT("slod_human"),
|
||||
RAGE_JOAAT("slod_small_quadped"), RAGE_JOAAT("slod_large_quadped"), RAGE_JOAAT("prop_distantcar_night"), RAGE_JOAAT("prop_distantcar_day"), RAGE_JOAAT("hei_bh1_08_details4_em_night"),
|
||||
RAGE_JOAAT("dt1_18_sq_night_slod"), RAGE_JOAAT("ss1_12_night_slod"), -1288391198, RAGE_JOAAT("h4_prop_bush_bgnvla_med_01"), RAGE_JOAAT("h4_prop_bush_bgnvla_lrg_01"),
|
||||
RAGE_JOAAT("h4_prop_bush_buddleia_low_01"), RAGE_JOAAT("h4_prop_bush_ear_aa"), RAGE_JOAAT("h4_prop_bush_ear_ab"), RAGE_JOAAT("h4_prop_bush_fern_low_01"),
|
||||
RAGE_JOAAT("h4_prop_bush_fern_tall_cc"), RAGE_JOAAT("h4_prop_bush_mang_ad"), RAGE_JOAAT("h4_prop_bush_mang_low_aa"), RAGE_JOAAT("h4_prop_bush_mang_low_ab"),
|
||||
RAGE_JOAAT("h4_prop_bush_seagrape_low_01"), RAGE_JOAAT("prop_h4_ground_cover"), RAGE_JOAAT("h4_prop_weed_groundcover_01"), RAGE_JOAAT("h4_prop_grass_med_01"),
|
||||
RAGE_JOAAT("h4_prop_grass_tropical_lush_01"), RAGE_JOAAT("h4_prop_grass_wiregrass_01"), RAGE_JOAAT("h4_prop_weed_01_plant"), RAGE_JOAAT("h4_prop_weed_01_row"),
|
||||
RAGE_JOAAT("urbanweeds02_l1"), RAGE_JOAAT("proc_forest_grass01"), RAGE_JOAAT("prop_small_bushyba"), RAGE_JOAAT("arbitergt"), RAGE_JOAAT("astron2"), RAGE_JOAAT("cyclone2"),
|
||||
RAGE_JOAAT("ignus2"), RAGE_JOAAT("s95"), RAGE_JOAAT("hc_gunman"), RAGE_JOAAT("v_res_d_dildo_a"), RAGE_JOAAT("v_res_d_dildo_b"), RAGE_JOAAT("v_res_d_dildo_c"),
|
||||
RAGE_JOAAT("v_res_d_dildo_d"), RAGE_JOAAT("v_res_d_dildo_e"), RAGE_JOAAT("v_res_d_dildo_f"), RAGE_JOAAT("v_res_skateboard"), RAGE_JOAAT("prop_battery_01"), RAGE_JOAAT("prop_barbell_01"),
|
||||
RAGE_JOAAT("prop_barbell_02"), RAGE_JOAAT("prop_bandsaw_01"), RAGE_JOAAT("prop_bbq_3"), RAGE_JOAAT("v_med_curtainsnewcloth2"), RAGE_JOAAT("bh1_07_flagpoles"),
|
||||
92962485, RAGE_JOAAT("ig_wade") };
|
||||
|
||||
constexpr uint32_t cage_models[] = { RAGE_JOAAT("prop_rub_cage01a"), RAGE_JOAAT("prop_fnclink_05crnr1"), RAGE_JOAAT("prop_gold_cont_01"), RAGE_JOAAT("prop_gold_cont_01b"),
|
||||
RAGE_JOAAT("prop_feeder1"), RAGE_JOAAT("stt_prop_stunt_tube_s"), RAGE_JOAAT("prop_feeder1_cr"), RAGE_JOAAT("p_cablecar_s") };
|
||||
|
||||
inline bool is_model_a_crash_model(uint32_t model) {
|
||||
for (auto iterator : crash_models)
|
||||
if (auto net_obj = g_pointers->m_get_net_object(mgr, object_id, true); net_obj && net_obj->m_object_type != (int16_t)object_type)
|
||||
{
|
||||
if (iterator == model) return true;
|
||||
}
|
||||
return false;
|
||||
notify::crash_blocked(src, "incorrect object type");
|
||||
return eAckCode::ACKCODE_FAIL;
|
||||
}
|
||||
|
||||
inline bool is_model_a_cage_model(uint32_t model) {
|
||||
for (auto iterator : cage_models)
|
||||
{
|
||||
if (iterator == model) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* get_node_from_object(rage::netSyncNodeBase* node)
|
||||
{
|
||||
constexpr uint64_t hash = CLASS_TO_MANGLED_NAME(T)""_fnv1a;
|
||||
if (node->IsParentNode())
|
||||
{
|
||||
for (auto child = node->m_first_child; child; child = child->m_next_sibling) {
|
||||
T* attach_node = get_node_from_object<T>(child);
|
||||
if (attach_node != nullptr)
|
||||
return attach_node;
|
||||
}
|
||||
}
|
||||
else if (node->IsDataNode())
|
||||
{
|
||||
if (typeid(*node).hash_code() == hash)
|
||||
return dynamic_cast<T*>(node);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool is_attachment_infinite(CPhysicalAttachDataNode* node, uint16_t object_id) {
|
||||
if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object)
|
||||
{
|
||||
if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree)
|
||||
{
|
||||
if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) {
|
||||
const auto attached_attach_node = get_node_from_object<CPhysicalAttachDataNode>(base_node);
|
||||
if (attached_attach_node && attached_attach_node->m_attached)
|
||||
{
|
||||
if (attached_attach_node->m_attached_to == object_id) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return is_attachment_infinite(attached_attach_node, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_ped_attachment_infinite(CPedAttachDataNode* node, uint16_t object_id) {
|
||||
if (rage::netObject* attached_object = (*g_pointers->m_network_object_mgr)->find_object_by_id(node->m_attached_to, false); attached_object)
|
||||
{
|
||||
if (rage::netSyncTree* tree = attached_object->GetSyncTree(); tree)
|
||||
{
|
||||
if (rage::netSyncNodeBase* base_node = tree->m_sync_node; base_node) {
|
||||
const auto attached_attach_node = get_node_from_object<CPedAttachDataNode>(base_node);
|
||||
if (attached_attach_node && attached_attach_node->m_attached)
|
||||
{
|
||||
if (attached_attach_node->m_attached_to == object_id) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return is_ped_attachment_infinite(attached_attach_node, object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_node(rage::netSyncNodeBase* node, CNetGamePlayer* sender, uint16_t object_id)
|
||||
{
|
||||
if (node->IsParentNode())
|
||||
{
|
||||
for (auto child = node->m_first_child; child; child = child->m_next_sibling) {
|
||||
if (check_node(child, sender, object_id))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (node->IsDataNode())
|
||||
{
|
||||
//LOG(INFO) << typeid(*node).name() << ": " << HEX_TO_UPPER(typeid(*node).hash_code()); //Use this to get hashes for each node
|
||||
switch (typeid(*node).hash_code()) {
|
||||
case "?AVCDoorCreationDataNode@@"_fnv1a: //CDoorCreationDataNode
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CDoorCreationDataNode*>(node);
|
||||
if (is_model_a_crash_model(creation_node->m_model))
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid door model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From: " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid door model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPickupCreationDataNode@@"_fnv1a: //CPickupCreationDataNode
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CPickupCreationDataNode*>(node);
|
||||
if (is_model_a_crash_model(creation_node->m_custom_model))
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid pickup model: Model: " << HEX_TO_UPPER(creation_node->m_custom_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid pickup model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_custom_model));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPhysicalAttachDataNode@@"_fnv1a: //CPhysicalAttachDataNode
|
||||
{
|
||||
const auto attach_node = dynamic_cast<CPhysicalAttachDataNode*>(node);
|
||||
if (attach_node->m_attached && attach_node->m_attached_to == object_id)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Infinite attachment: Node: " << typeid(*node).name() << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Infinite attachment from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name()));
|
||||
return true;
|
||||
}
|
||||
else if (attach_node->m_attached && is_attachment_infinite(attach_node, object_id))
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Infinite attachment v2: Node: " << typeid(*node).name() << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Infinite attachment v2 from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name()));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPedCreationDataNode@@"_fnv1a: //CPedCreationDataNode
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CPedCreationDataNode*>(node);
|
||||
if (is_model_a_crash_model(creation_node->m_model))
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid ped model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid ped model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model));
|
||||
return true;
|
||||
}
|
||||
else if (creation_node->m_has_prop && is_model_a_crash_model(creation_node->m_prop_model)) {
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid ped prop model: Model: " << HEX_TO_UPPER(creation_node->m_prop_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid ped prop model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_prop_model));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPedAttachDataNode@@"_fnv1a: //CPedAttachDataNode
|
||||
{
|
||||
const auto attach_node = dynamic_cast<CPedAttachDataNode*>(node);
|
||||
if (attach_node->m_attached && attach_node->m_attached_to == object_id)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Infinite ped attachment: Node: " << typeid(*node).name() << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Infinite ped attachment from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name()));
|
||||
return true;
|
||||
}
|
||||
else if (attach_node->m_attached && is_ped_attachment_infinite(attach_node, object_id))
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Infinite ped attachment v2: Node: " << typeid(*node).name() << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Infinite ped attachment v2 from {}", sender->get_name()), std::format("Node: {}", typeid(*node).name()));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPedInventoryDataNode@@"_fnv1a://CPedInventoryDataNode
|
||||
{
|
||||
const auto inventory_node = dynamic_cast<CPedInventoryDataNode*>(node);
|
||||
if (inventory_node->m_num_items > 105 || inventory_node->m_num_ammos > 65)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid inventory data from: " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid inventory data from {}", sender->get_name()), "Invalid inventory data.");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCVehicleCreationDataNode@@"_fnv1a: //CVehicleCreationDataNode
|
||||
{
|
||||
const auto vehicle_creation_node = dynamic_cast<CVehicleCreationDataNode*>(node);
|
||||
if (is_model_a_crash_model(vehicle_creation_node->m_model)) {
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid vehicle model: Model: " << HEX_TO_UPPER(vehicle_creation_node->m_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid vehicle model from {}", sender->get_name()), std::format("Model: 0x{:x}", vehicle_creation_node->m_model));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCVehicleGadgetDataNode@@"_fnv1a: //CVehicleGadgetDataNode
|
||||
{
|
||||
const auto vehicle_gadget_node = dynamic_cast<CVehicleGadgetDataNode*>(node);
|
||||
if (vehicle_gadget_node->m_gadget_count > 2)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid vehicle gadget count from: " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid vehicle gadget count from {}", sender->get_name()), "Invalid vehicle gadget count.");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCObjectCreationDataNode@@"_fnv1a: //CObjectCreationDataNode
|
||||
{
|
||||
const auto creation_node = dynamic_cast<CObjectCreationDataNode*>(node);
|
||||
if (is_model_a_crash_model(creation_node->m_model)) {
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid object model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid object model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model));
|
||||
return true;
|
||||
}
|
||||
else if (is_model_a_cage_model(creation_node->m_model)) {
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Cage model: Model: " << HEX_TO_UPPER(creation_node->m_model) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Cage model from {}", sender->get_name()), std::format("Model: 0x{:x}", creation_node->m_model));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCPlayerAppearanceDataNode@@"_fnv1a: //CPlayerAppearanceDataNode
|
||||
{
|
||||
const auto player_appearance_node = dynamic_cast<CPlayerAppearanceDataNode*>(node);
|
||||
if (is_model_a_crash_model(player_appearance_node->m_model_hash)) {
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid player model: Model:" << HEX_TO_UPPER(player_appearance_node->m_model_hash) << " From : " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid player model from {}", sender->get_name()), std::format("Model: 0x{:x}", player_appearance_node->m_model_hash));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCSectorDataNode@@"_fnv1a: //CSectorDataNode
|
||||
{
|
||||
const auto sector_node = dynamic_cast<CSectorDataNode*>(node);
|
||||
if (sector_node->m_pos_x == 712 || sector_node->m_pos_y == 712 || sector_node->m_pos_z == 712)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid sector position from: " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid sector position from {}", sender->get_name()), "Invalid sector position.");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "?AVCDynamicEntityGameStateDataNode@@"_fnv1a: //CDynamicEntityGameStateDataNode
|
||||
{
|
||||
const auto game_state_node = dynamic_cast<CDynamicEntityGameStateDataNode*>(node);
|
||||
if (game_state_node->m_decor_count > 11)
|
||||
{
|
||||
if (g->notifications.invalid_sync.log)
|
||||
LOG(WARNING) << "Invalid decorator count from: " << sender->get_name();
|
||||
if (g->notifications.invalid_sync.notify)
|
||||
g_notification_service->push_warning(std::format("Invalid decorator count from {}", sender->get_name()), "Invalid decorator count.");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t hooks::received_clone_sync(CNetworkObjectMgr* mgr, CNetGamePlayer* src, CNetGamePlayer* dst, eObjType sync_type, uint16_t obj_id, rage::datBitBuffer* buffer, uint16_t unk, uint32_t timestamp)
|
||||
{
|
||||
if (auto sync_tree = g_pointers->m_get_sync_tree_for_type(mgr, sync_type); sync_tree && *g_pointers->m_is_session_started)
|
||||
{
|
||||
if (auto net_obj = g_pointers->m_get_net_object(mgr, obj_id, true); net_obj)
|
||||
{
|
||||
auto tree_name = g_pointers->m_get_sync_type_info(sync_type, 0);
|
||||
|
||||
if (sync_type < eObjType::carObjType || sync_type > eObjType::unkObjType14)
|
||||
{
|
||||
if (g->notifications.out_of_allowed_range_sync_type.log)
|
||||
LOG(WARNING) << "Out of Bounds sync: Type: " << sync_type << " Tree name: " << tree_name << " From: " << src->get_name();
|
||||
if (g->notifications.out_of_allowed_range_sync_type.notify)
|
||||
g_notification_service->push_warning(std::format("Out Of Allowed Sync Range from {}", src->get_name()), std::format("Type {} in sync tree {}", std::uint16_t(sync_type), tree_name));
|
||||
|
||||
return g_hooking->get_original<received_clone_sync>()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp);
|
||||
}
|
||||
|
||||
if (net_obj->m_object_type != sync_type)
|
||||
{
|
||||
if (g->notifications.mismatch_sync_type.log)
|
||||
LOG(WARNING) << "Mismatch sync: Type: " << sync_type << " Tree name: " << tree_name << " From: " << src->get_name();
|
||||
if (g->notifications.mismatch_sync_type.notify)
|
||||
g_notification_service->push_warning(std::format("Mismatch Sync from {}", src->get_name()), std::format("Type {} in sync tree {}", std::uint16_t(sync_type), tree_name));
|
||||
|
||||
return eSyncReply::WrongOwner;
|
||||
}
|
||||
|
||||
if (auto game_obj = net_obj->GetGameObject(); game_obj)
|
||||
{
|
||||
if (const auto model_info = game_obj->m_model_info; model_info)
|
||||
{
|
||||
// sync_type is telling us it's a vehicle
|
||||
// let's check if it's actually a vehicle according to our game...
|
||||
if (((sync_type >= eObjType::bikeObjType && sync_type <= eObjType::heliObjType)
|
||||
|| (sync_type >= eObjType::planeObjType && sync_type <= eObjType::submarineObjType)
|
||||
|| (sync_type >= eObjType::trailerObjType && sync_type <= eObjType::trainObjType))
|
||||
&& model_info->m_model_type != eModelType::Vehicle)
|
||||
{
|
||||
return eSyncReply::CantApplyData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall through? Should not happen but let's try to be safe
|
||||
return eSyncReply::CantApplyData;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = buffer->m_bitsRead;
|
||||
g_pointers->m_read_bitbuffer_into_sync_tree(sync_tree, 2, 0, buffer, 0);
|
||||
buffer->Seek(pos);
|
||||
|
||||
//LOG(INFO) << typeid(*tree).name() << ": " << HEX_TO_UPPER(typeid(*tree).hash_code()); //Use this to get hashes for each tree
|
||||
|
||||
if (sync_tree->m_child_node_count && check_node(sync_tree->m_sync_node, src, obj_id))
|
||||
{
|
||||
return eSyncReply::CantApplyData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return g_hooking->get_original<received_clone_sync>()(mgr, src, dst, sync_type, obj_id, buffer, unk, timestamp);
|
||||
g->m_syncing_player = src;
|
||||
return g_hooking->get_original<received_clone_sync>()(mgr, src, dst, object_type, object_id, buffer, unk, timestamp);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "hooking.hpp"
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
#include "gta/script_id.hpp"
|
||||
#include "util/notify.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -32,7 +33,6 @@ namespace big
|
||||
if (event_id > 91u)
|
||||
{
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -81,15 +81,10 @@ namespace big
|
||||
uint16_t unk2 = buffer->Read<uint16_t>(13);
|
||||
uint32_t action = buffer->Read<uint32_t>(8);
|
||||
|
||||
if (action >= 15 && action <= 18 || action == 33)
|
||||
if ((action >= 15 && action <= 18) || action == 33)
|
||||
{
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
|
||||
if (g->notifications.received_event.vehicle_temp_action.log)
|
||||
LOG(INFO) << "RECEIVED_EVENT_HANDLER : " << source_player->get_name() << " sent TASK_VEHICLE_TEMP_ACTION crash.";
|
||||
if (g->notifications.received_event.vehicle_temp_action.notify)
|
||||
g_notification_service->push_error("Protections", std::format("{} sent TASK_VEHICLE_TEMP_ACTION crash.", source_player->get_name()));
|
||||
|
||||
notify::crash_blocked(source_player, "vehicle temp action");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -172,7 +167,6 @@ namespace big
|
||||
break;
|
||||
}
|
||||
// player sending this event is a modder
|
||||
case eNetworkEvents::NETWORK_CHECK_CODE_CRCS_EVENT:
|
||||
case eNetworkEvents::REPORT_MYSELF_EVENT:
|
||||
{
|
||||
if (g->notifications.received_event.modder_detect.log)
|
||||
@ -180,6 +174,9 @@ namespace big
|
||||
if (g->notifications.received_event.modder_detect.notify)
|
||||
g_notification_service->push_warning("Protections", std::format("{} sent out a modder event.", source_player->get_name()));
|
||||
|
||||
if (auto plyr = g_player_service->get_by_id(source_player->m_player_id))
|
||||
session::add_infraction(plyr, Infraction::TRIGGERED_ANTICHEAT);
|
||||
|
||||
break;
|
||||
}
|
||||
case eNetworkEvents::REQUEST_CONTROL_EVENT:
|
||||
@ -202,7 +199,7 @@ namespace big
|
||||
case eNetworkEvents::SCRIPT_WORLD_STATE_EVENT:
|
||||
{
|
||||
auto type = buffer->Read<WorldStateDataType>(4);
|
||||
(void)buffer->Read<bool>(1);
|
||||
buffer->Read<bool>(1);
|
||||
CGameScriptId id;
|
||||
script_id_deserialize(id, *buffer);
|
||||
|
||||
@ -221,7 +218,8 @@ namespace big
|
||||
if (type != 7)
|
||||
{
|
||||
// most definitely a crash
|
||||
g_notification_service->push_error("Protections", std::format("{} sent rope crash.", source_player->get_name()));
|
||||
LOG(INFO) << std::hex << std::uppercase << "0x" << id.m_hash;
|
||||
notify::crash_blocked(source_player, "rope");
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
@ -234,7 +232,7 @@ namespace big
|
||||
|
||||
if (unk2 == 0 && (unk3 == 0 || unk3 == 103))
|
||||
{
|
||||
g_notification_service->push_error("Protections", std::format("{} sent SCRIPT_WORLD_STATE_EVENT crash.", source_player->get_name()));
|
||||
notify::crash_blocked(source_player, "pop group override");
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
@ -250,6 +248,7 @@ namespace big
|
||||
|
||||
if (hash == RAGE_JOAAT("WEAPON_UNARMED"))
|
||||
{
|
||||
notify::crash_blocked(source_player, "remove unarmed");
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
@ -278,6 +277,35 @@ namespace big
|
||||
buffer->Seek(0);
|
||||
break;
|
||||
}
|
||||
case eNetworkEvents::GIVE_CONTROL_EVENT:
|
||||
{
|
||||
uint32_t timestamp = buffer->Read<uint32_t>(32);
|
||||
int count = buffer->Read<int>(2);
|
||||
bool unk = buffer->Read<bool>(1);
|
||||
|
||||
if (count > 3)
|
||||
{
|
||||
count = 3;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int net_id = buffer->Read<int>(13);
|
||||
eNetObjType object_type = buffer->Read<eNetObjType>(4);
|
||||
int unk = buffer->Read<int>(3);
|
||||
|
||||
if (object_type < eNetObjType::NET_OBJ_TYPE_AUTOMOBILE || object_type > eNetObjType::NET_OBJ_TYPE_TRAIN)
|
||||
{
|
||||
notify::crash_blocked(source_player, "out of bounds give control type");
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->Seek(0);
|
||||
g->m_syncing_player = source_player;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
|
||||
namespace big
|
||||
@ -276,8 +277,9 @@ namespace big
|
||||
case eRemoteEvent::SHKick:
|
||||
if (g->protections.script_events.network_bail)
|
||||
{
|
||||
if (auto plyr = g_player_service->get_by_id(player->m_player_id))
|
||||
session::add_infraction(plyr, Infraction::TRIED_KICK_PLAYER);
|
||||
format_string(player_name, "Network Bail", notify.network_bail.log, notify.network_bail.notify);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -0,0 +1,58 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta/net_game_event.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include <datanodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
constexpr uint32_t NULL_INTERIOR = 0x0FFFCFFFF;
|
||||
|
||||
void hooks::serialize_dynamic_entity_game_state_data_node(CDynamicEntityGameStateDataNode* node, rage::CSyncDataBase* data)
|
||||
{
|
||||
data->SerializeBool(&node->unk_00C5);
|
||||
if (node->unk_00C5 && !data->IsSizeCalculator())
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_interior_index, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool is_null_interior = node->m_interior_index == NULL_INTERIOR;
|
||||
data->SerializeBool(&is_null_interior);
|
||||
|
||||
if (!is_null_interior || data->IsSizeCalculator())
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_interior_index, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
node->m_interior_index = NULL_INTERIOR;
|
||||
}
|
||||
}
|
||||
|
||||
data->SerializeBool(&node->unk_00C4);
|
||||
|
||||
bool has_decors = node->m_decor_count != 0;
|
||||
data->SerializeBool(&has_decors);
|
||||
|
||||
if (has_decors || data->IsSizeCalculator())
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_decor_count, 4);
|
||||
|
||||
if (data->IsSizeCalculator())
|
||||
node->m_decor_count = 11;
|
||||
|
||||
if (node->m_decor_count > 11)
|
||||
{
|
||||
notify::crash_blocked(g->m_syncing_player, "out of bounds decorator count");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->m_decor_count; i++)
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_decors[i].m_type, 3);
|
||||
data->SerializeDwordAlt(&node->m_decors[i].m_value, 32);
|
||||
data->SerializeDwordAlt(&node->m_decors[i].m_name_hash, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/hooks/protections/serialize_ped_inventory_data_node.cpp
Normal file
49
src/hooks/protections/serialize_ped_inventory_data_node.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta/net_game_event.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include <datanodes/ped/CPedInventoryDataNode.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
void hooks::serialize_ped_inventory_data_node(CPedInventoryDataNode* node, rage::CSyncDataBase* data)
|
||||
{
|
||||
if (data->IsSizeCalculator())
|
||||
{
|
||||
node->m_num_items = 105;
|
||||
node->m_num_ammos = 65;
|
||||
}
|
||||
|
||||
data->SerializeDwordAlt(&node->m_num_items, 7);
|
||||
if (node->m_num_items > 105)
|
||||
{
|
||||
notify::crash_blocked(g->m_syncing_player, "out of bounds inventory item count");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->m_num_items; i++)
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_items[i], 9);
|
||||
node->unk_1680[i] = 0;
|
||||
node->unk_16E9[i] = 0;
|
||||
}
|
||||
|
||||
data->SerializeDwordAlt(&node->m_num_ammos, 7);
|
||||
data->SerializeBool(&node->m_ammo_all_infinite);
|
||||
if (node->m_num_ammos > 65)
|
||||
{
|
||||
notify::crash_blocked(g->m_syncing_player, "out of bounds inventory ammo count");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->m_num_ammos; i++)
|
||||
{
|
||||
data->SerializeDwordAlt(&node->m_ammos[i], 9);
|
||||
if (node->m_ammo_all_infinite && !data->IsSizeCalculator())
|
||||
continue;
|
||||
data->SerializeBool(&node->m_infinite_ammos[i]);
|
||||
if (node->m_infinite_ammos[i] && !data->IsSizeCalculator())
|
||||
continue;
|
||||
data->SerializeDwordAlt(&node->m_ammo_quantities[i], 14);
|
||||
}
|
||||
}
|
||||
}
|
49
src/hooks/protections/serialize_vehicle_gadget_data_node.cpp
Normal file
49
src/hooks/protections/serialize_vehicle_gadget_data_node.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta/net_game_event.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include <datanodes/vehicle/CVehicleGadgetDataNode.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
void hooks::serialize_vehicle_gadget_data_node(CVehicleGadgetDataNode* node, rage::CSyncDataBase* data)
|
||||
{
|
||||
data->SerializeBool(&node->m_has_parent_offset);
|
||||
if (node->m_has_parent_offset || data->IsSizeCalculator())
|
||||
{
|
||||
data->SerializeSignedFloat((float*)&node->m_parent_offset_x, 24.0f, 14);
|
||||
data->SerializeSignedFloat((float*)&node->m_parent_offset_y, 24.0f, 14);
|
||||
data->SerializeSignedFloat((float*)&node->m_parent_offset_z, 24.0f, 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
node->m_parent_offset_x = 0;
|
||||
node->m_parent_offset_y = 0;
|
||||
node->m_parent_offset_z = 0;
|
||||
node->m_parent_offset_w = 0;
|
||||
}
|
||||
|
||||
data->SerializeDwordAlt(&node->m_gadget_count, 2);
|
||||
|
||||
if (data->IsSizeCalculator())
|
||||
node->m_gadget_count = 2;
|
||||
|
||||
if (node->m_gadget_count > 2)
|
||||
{
|
||||
notify::crash_blocked(g->m_syncing_player, "out of bounds vehicle gadget count");
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->m_gadget_count; i++)
|
||||
{
|
||||
data->SerializeDwordAlt((uint32_t*)&node->m_gadget_data[i].m_gadget_type, 3);
|
||||
|
||||
int size;
|
||||
if (data->IsSizeCalculator())
|
||||
size = 94;
|
||||
else
|
||||
size = g_pointers->m_get_vehicle_gadget_array_size(node->m_gadget_data[i].m_gadget_type);
|
||||
|
||||
data->SerializeArray(&node->m_gadget_data[i].m_data, size);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include "hooking.hpp"
|
||||
#include <datanodes/player/CPlayerGamerDataNode.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
17
src/json_util.hpp
Normal file
17
src/json_util.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
template <typename ValueType>
|
||||
static inline void set_from_key_or_default(const nlohmann::json& j, const char* key, ValueType& value, ValueType default_value = {})
|
||||
{
|
||||
if (j.contains(key))
|
||||
{
|
||||
j.at(key).get_to(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = default_value;
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
#include "services/model_preview/model_preview_service.hpp"
|
||||
#include "services/vehicle/handling_service.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
{
|
||||
@ -86,6 +87,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
auto handling_service_instance = std::make_unique<handling_service>();
|
||||
auto gui_service_instance = std::make_unique<gui_service>();
|
||||
auto script_patcher_service_instance = std::make_unique<script_patcher_service>();
|
||||
auto player_database_service_instance = std::make_unique<player_database_service>();
|
||||
LOG(INFO) << "Registered service instances...";
|
||||
|
||||
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func, "GUI", false));
|
||||
@ -133,6 +135,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
|
||||
thread_pool_instance.reset();
|
||||
LOG(INFO) << "Thread pool uninitialized.";
|
||||
|
||||
player_database_service_instance.reset();
|
||||
LOG(INFO) << "Player Database Service reset.";
|
||||
script_patcher_service_instance.reset();
|
||||
LOG(INFO) << "Script Patcher Service reset.";
|
||||
gui_service_instance.reset();
|
||||
|
18
src/packet.cpp
Normal file
18
src/packet.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "common.hpp"
|
||||
#include "packet.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include <network/Network.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
packet::packet() :
|
||||
m_buffer(m_data, 0x4000)
|
||||
{
|
||||
}
|
||||
|
||||
void packet::send(uint32_t msg_id)
|
||||
{
|
||||
g_pointers->m_queue_packet(gta_util::get_network()->m_game_session_ptr->m_net_connection_mgr, msg_id, m_data, (m_buffer.m_curBit + 7) >> 3, 1, nullptr);
|
||||
}
|
||||
}
|
51
src/packet.hpp
Normal file
51
src/packet.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "gta/net_game_event.hpp"
|
||||
#include "network/CNetGamePlayer.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class packet
|
||||
{
|
||||
public:
|
||||
char m_data[0x4000]{};
|
||||
rage::datBitBuffer m_buffer;
|
||||
|
||||
packet();
|
||||
void send(uint32_t msg_id);
|
||||
|
||||
inline operator rage::datBitBuffer& ()
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void write(T data, int length)
|
||||
{
|
||||
m_buffer.Write<T>(data, length);
|
||||
}
|
||||
|
||||
inline void write_message(rage::eNetMessage message)
|
||||
{
|
||||
write<int>(0x3246, 14);
|
||||
if ((int)message > 0xFF)
|
||||
{
|
||||
write<bool>(true, 1);
|
||||
write<rage::eNetMessage>(message, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
write<bool>(false, 1);
|
||||
write<rage::eNetMessage>(message, 8);
|
||||
}
|
||||
}
|
||||
|
||||
inline void write_peer_id(std::uint64_t peer_id)
|
||||
{
|
||||
char b[8];
|
||||
rage::datBitBuffer buf(b, 8);
|
||||
buf.WriteQWord(peer_id, 64);
|
||||
m_buffer.WriteArray(b, 8 * buf.GetDataLength());
|
||||
}
|
||||
};
|
||||
}
|
@ -314,6 +314,18 @@ namespace big
|
||||
m_assign_physical_index = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Received Clone Create
|
||||
main_batch.add("RCC", "48 8B C4 66 44 89 48", [this](memory::handle ptr)
|
||||
{
|
||||
m_received_clone_create = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Can Apply Data
|
||||
main_batch.add("CAD", "49 8B CE FF 50 70 84 C0 74 31 33 FF", [this](memory::handle ptr)
|
||||
{
|
||||
m_can_apply_data = ptr.sub(0x2C).as<PVOID>();
|
||||
});
|
||||
|
||||
// Received clone sync & Get sync tree for type & Get net object for player & Get sync type info & Get net object
|
||||
main_batch.add("RCS/GSTFT/GNOFP/GNO/GSTI", "4C 8B FA 41 0F B7 D1", [this](memory::handle ptr)
|
||||
{
|
||||
@ -482,6 +494,54 @@ namespace big
|
||||
m_communications = ptr.add(3).rip().as<CCommunications**>();
|
||||
});
|
||||
|
||||
// Serialize Dynamic Entity Game State Data Node (that's a mouthful!)
|
||||
main_batch.add("SDEGSDN", "48 89 5C 24 18 55 56 57 41 56 41 57 48 83 EC 20 48 8B 02 48 8D 99", [this](memory::handle ptr)
|
||||
{
|
||||
m_serialize_dynamic_entity_game_state_data_node = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Serialize Ped Inventory Data Node
|
||||
main_batch.add("SPIDN", "48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 54 41 56 41 57 48 83 EC 20 48 8B 02 48 8B F1 48 8B CA 48 8B FA FF 90", [this](memory::handle ptr)
|
||||
{
|
||||
m_serialize_ped_inventory_data_node = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Serialize Vehicle Gadget Data Node
|
||||
main_batch.add("SVGDN", "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 83 EC 30 48 8B 02 48 8D", [this](memory::handle ptr)
|
||||
{
|
||||
m_serialize_vehicle_gadget_data_node = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Get Vehicle Gadget Array Size
|
||||
main_batch.add("GVGAS", "40 53 48 83 EC 40 33 DB E8", [this](memory::handle ptr)
|
||||
{
|
||||
m_get_vehicle_gadget_array_size = ptr.as<functions::get_vehicle_gadget_array_size>();
|
||||
});
|
||||
|
||||
// Handle Join Request
|
||||
main_batch.add("HJR", "48 8B C4 4C 89 48 20 4C 89 40 18 48 89 50 10 55 53 56 57 41 54 41 55 41 56 41 57 48 8D A8 E8 FE", [this](memory::handle ptr)
|
||||
{
|
||||
m_handle_join_request = ptr.as<PVOID>();
|
||||
});
|
||||
|
||||
// Handle Join Request
|
||||
main_batch.add("WJRD", "E8 ? ? ? ? 48 8D 8D 90 00 00 00 F6 D8", [this](memory::handle ptr)
|
||||
{
|
||||
m_write_join_response_data = ptr.add(1).rip().as<functions::write_join_response_data>();
|
||||
});
|
||||
|
||||
// Queue Packet
|
||||
main_batch.add("QP", "E8 ? ? ? ? 84 C0 74 4D B3 01", [this](memory::handle ptr)
|
||||
{
|
||||
m_queue_packet = ptr.add(1).rip().as<functions::queue_packet>();
|
||||
});
|
||||
|
||||
// Sort Session Details
|
||||
main_batch.add("SGS", "C3 0F 2E 42 0C", [this](memory::handle ptr)
|
||||
{
|
||||
m_sort_session_details = ptr.sub(0x10).as<PVOID>();
|
||||
});
|
||||
|
||||
auto mem_region = memory::module("GTA5.exe");
|
||||
main_batch.run(mem_region);
|
||||
|
||||
|
@ -99,7 +99,9 @@ namespace big
|
||||
// Received Event Signatures END
|
||||
|
||||
//Sync Signatures START
|
||||
PVOID m_received_clone_create;
|
||||
PVOID m_received_clone_sync;
|
||||
PVOID m_can_apply_data;
|
||||
functions::get_sync_tree_for_type m_get_sync_tree_for_type{};
|
||||
functions::get_sync_type_info m_get_sync_type_info{};
|
||||
functions::get_net_object m_get_net_object{};
|
||||
@ -150,8 +152,20 @@ namespace big
|
||||
rage::rlGamerInfo* m_player_info_gamer_info{}; // the gamer info that is applied to CPlayerInfo
|
||||
CCommunications** m_communications{};
|
||||
|
||||
PVOID m_update_presence_attribute_int{};
|
||||
PVOID m_update_presence_attribute_string{};
|
||||
PVOID m_update_presence_attribute_int;
|
||||
PVOID m_update_presence_attribute_string;
|
||||
|
||||
PVOID m_serialize_dynamic_entity_game_state_data_node;
|
||||
PVOID m_serialize_ped_inventory_data_node;
|
||||
PVOID m_serialize_vehicle_gadget_data_node;
|
||||
functions::get_vehicle_gadget_array_size m_get_vehicle_gadget_array_size;
|
||||
|
||||
PVOID m_handle_join_request;
|
||||
functions::write_join_response_data m_write_join_response_data;
|
||||
|
||||
functions::queue_packet m_queue_packet;
|
||||
|
||||
PVOID m_sort_session_details;
|
||||
};
|
||||
|
||||
inline pointers* g_pointers{};
|
||||
|
@ -30,6 +30,7 @@ namespace big
|
||||
NETWORK,
|
||||
SESSION,
|
||||
SPOOFING,
|
||||
PLAYER_DATABASE,
|
||||
|
||||
SETTINGS,
|
||||
CONTEXT_MENU_SETTINGS,
|
||||
@ -78,6 +79,7 @@ namespace big
|
||||
{tabs::NETWORK, { "Network", nullptr, {
|
||||
{ tabs::SPOOFING, { "Spoofing", view::spoofing }},
|
||||
{ tabs::SESSION, { "Session", view::session }},
|
||||
{ tabs::PLAYER_DATABASE, { "Player Database", view::player_database }},
|
||||
}}},
|
||||
{tabs::SETTINGS, { "Settings", view::settings, {
|
||||
{ tabs::CONTEXT_MENU_SETTINGS, { "Context Menu", view::context_menu_settings}},
|
||||
|
@ -19,17 +19,17 @@ namespace big
|
||||
|
||||
void notification_service::push(std::string title, std::string message)
|
||||
{
|
||||
this->push({ NotificationType::INFO, title, message, std::chrono::system_clock::now(), 3000.f , 1.f});
|
||||
this->push({ NotificationType::INFO, title, message, std::chrono::system_clock::now(), 5000.f , 1.f});
|
||||
}
|
||||
|
||||
void notification_service::push_warning(std::string title, std::string message)
|
||||
{
|
||||
this->push({ NotificationType::WARNING, title, message, std::chrono::system_clock::now(), 3000.f , 1.f });
|
||||
this->push({ NotificationType::WARNING, title, message, std::chrono::system_clock::now(), 7000.f , 1.f });
|
||||
}
|
||||
|
||||
void notification_service::push_error(std::string title, std::string message)
|
||||
{
|
||||
this->push({ NotificationType::DANGER, title, message, std::chrono::system_clock::now(), 3000.f , 1.f });
|
||||
this->push({ NotificationType::DANGER, title, message, std::chrono::system_clock::now(), 7000.f , 1.f });
|
||||
}
|
||||
|
||||
std::vector<notification> notification_service::get()
|
||||
|
39
src/services/player_database/persistent_player.hpp
Normal file
39
src/services/player_database/persistent_player.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "core/data/infractions.hpp"
|
||||
#include <unordered_set>
|
||||
#include "json_util.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
struct persistent_player
|
||||
{
|
||||
std::string name;
|
||||
std::uint64_t rockstar_id = 0;
|
||||
bool block_join = false;
|
||||
int block_join_reason = 1;
|
||||
bool is_modder = false;
|
||||
std::unordered_set<int> infractions;
|
||||
};
|
||||
|
||||
static void to_json(nlohmann::json& j, const persistent_player& player)
|
||||
{
|
||||
j = nlohmann::json{
|
||||
{ "name", player.name },
|
||||
{ "rockstar_id", player.rockstar_id },
|
||||
{ "block_join", player.block_join },
|
||||
{ "block_join_reason", player.block_join_reason },
|
||||
{ "is_modder", player.is_modder },
|
||||
{ "infractions", player.infractions },
|
||||
};
|
||||
};
|
||||
|
||||
static void from_json(const nlohmann::json& j, persistent_player& player)
|
||||
{
|
||||
set_from_key_or_default(j, "name", player.name);
|
||||
set_from_key_or_default(j, "rockstar_id", player.rockstar_id);
|
||||
set_from_key_or_default(j, "block_join", player.block_join);
|
||||
set_from_key_or_default(j, "block_join_reason", player.block_join_reason);
|
||||
set_from_key_or_default(j, "is_modder", player.is_modder);
|
||||
set_from_key_or_default(j, "infractions", player.infractions);
|
||||
}
|
||||
};
|
98
src/services/player_database/player_database_service.cpp
Normal file
98
src/services/player_database/player_database_service.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "player_database_service.hpp"
|
||||
#include "file_manager.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
player_database_service::player_database_service() :
|
||||
m_file_path(g_file_manager->get_project_file("./players.json").get_path())
|
||||
{
|
||||
load();
|
||||
g_player_database_service = this;
|
||||
}
|
||||
|
||||
player_database_service::~player_database_service()
|
||||
{
|
||||
g_player_database_service = nullptr;
|
||||
}
|
||||
|
||||
void player_database_service::save()
|
||||
{
|
||||
nlohmann::json json;
|
||||
|
||||
for (auto& [rid, player] : m_players)
|
||||
{
|
||||
json[std::to_string(rid)] = player;
|
||||
}
|
||||
|
||||
std::ofstream file_stream(m_file_path);
|
||||
file_stream << json;
|
||||
}
|
||||
|
||||
void player_database_service::load()
|
||||
{
|
||||
m_selected = nullptr;
|
||||
if (std::filesystem::exists(m_file_path))
|
||||
{
|
||||
std::ifstream file_stream(m_file_path);
|
||||
|
||||
nlohmann::json json;
|
||||
file_stream >> json;
|
||||
file_stream.close();
|
||||
|
||||
for (auto& p : json.items())
|
||||
{
|
||||
m_players[std::stoi(p.key())] = p.value().get<persistent_player>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::uint64_t, persistent_player>& player_database_service::get_players()
|
||||
{
|
||||
return m_players;
|
||||
}
|
||||
|
||||
persistent_player* player_database_service::get_player_by_rockstar_id(std::uint64_t rockstar_id)
|
||||
{
|
||||
if (m_players.contains(rockstar_id))
|
||||
return &m_players[rockstar_id];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
persistent_player* player_database_service::get_or_create_player(player_ptr player)
|
||||
{
|
||||
if (m_players.contains(player->get_net_data()->m_gamer_handle_2.m_rockstar_id))
|
||||
return &m_players[player->get_net_data()->m_gamer_handle_2.m_rockstar_id];
|
||||
else
|
||||
{
|
||||
m_players[player->get_net_data()->m_gamer_handle_2.m_rockstar_id] = { player->get_name(), player->get_net_data()->m_gamer_handle_2.m_rockstar_id };
|
||||
save();
|
||||
return &m_players[player->get_net_data()->m_gamer_handle_2.m_rockstar_id];
|
||||
}
|
||||
}
|
||||
|
||||
void player_database_service::update_rockstar_id(std::uint64_t old, std::uint64_t _new)
|
||||
{
|
||||
auto player = m_players.extract(old);
|
||||
player.key() = _new;
|
||||
|
||||
m_players.insert(std::move(player));
|
||||
}
|
||||
|
||||
void player_database_service::remove_rockstar_id(std::uint64_t rockstar_id)
|
||||
{
|
||||
if (m_selected && m_selected->rockstar_id == rockstar_id)
|
||||
m_selected = nullptr;
|
||||
|
||||
m_players.erase(rockstar_id);
|
||||
}
|
||||
|
||||
void player_database_service::set_selected(persistent_player* selected)
|
||||
{
|
||||
m_selected = selected;
|
||||
}
|
||||
|
||||
persistent_player* player_database_service::get_selected()
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
}
|
31
src/services/player_database/player_database_service.hpp
Normal file
31
src/services/player_database/player_database_service.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "persistent_player.hpp"
|
||||
#include "services/players/player.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class player_database_service
|
||||
{
|
||||
std::unordered_map<std::uint64_t, persistent_player> m_players;
|
||||
persistent_player* m_selected = nullptr;
|
||||
|
||||
public:
|
||||
std::filesystem::path m_file_path;
|
||||
player_database_service();
|
||||
~player_database_service();
|
||||
|
||||
void save();
|
||||
void load();
|
||||
|
||||
std::unordered_map<std::uint64_t, persistent_player>& get_players();
|
||||
persistent_player* get_player_by_rockstar_id(std::uint64_t rockstar_id);
|
||||
persistent_player* get_or_create_player(player_ptr player);
|
||||
void update_rockstar_id(std::uint64_t old, std::uint64_t _new);
|
||||
void remove_rockstar_id(std::uint64_t rockstar_id);
|
||||
|
||||
void set_selected(persistent_player* selected);
|
||||
persistent_player* get_selected();
|
||||
};
|
||||
|
||||
inline player_database_service* g_player_database_service;
|
||||
}
|
@ -45,6 +45,10 @@ namespace big
|
||||
std::chrono::system_clock::time_point m_last_transition_msg_sent{};
|
||||
int m_num_failed_transition_attempts = 0;
|
||||
|
||||
bool is_modder = false;
|
||||
bool block_join = false;
|
||||
int block_join_reason = 0;
|
||||
|
||||
protected:
|
||||
bool equals(const CNetGamePlayer* net_game_player) const;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "natives.hpp"
|
||||
#include "json_util.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -28,19 +28,6 @@ namespace big
|
||||
};
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
static void set_from_key_or_default(const nlohmann::json& j, const char* key, ValueType& value, ValueType default_value = {})
|
||||
{
|
||||
if (j.contains(key))
|
||||
{
|
||||
j.at(key).get_to(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = default_value;
|
||||
}
|
||||
}
|
||||
|
||||
static void from_json(const nlohmann::json& j, model_attachment& attachment)
|
||||
{
|
||||
set_from_key_or_default(j, "model_hash", attachment.model_hash);
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "natives.hpp"
|
||||
#include "core/data/model_attachment.hpp"
|
||||
#include "model_attachment.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "network/CNetGamePlayer.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
#include "session.hpp"
|
||||
|
||||
namespace big::notify
|
||||
{
|
||||
@ -13,18 +14,22 @@ namespace big::notify
|
||||
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
|
||||
}
|
||||
|
||||
// deprecated/unused
|
||||
inline void blocked_event(const char* name, Player player)
|
||||
inline void crash_blocked(CNetGamePlayer* player, const char* crash)
|
||||
{
|
||||
char msg[128];
|
||||
if (player)
|
||||
{
|
||||
g_notification_service->push_error("Protections", std::format("Blocked {} crash from {}", crash, player->get_name()));
|
||||
LOG(WARNING) << "Blocked " << crash << " crash from " << player->get_name() << " (" << (player->get_net_data() ? player->get_net_data()->m_gamer_handle_2.m_rockstar_id : 0) << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_error("Protections", std::format("Blocked {} crash from unknown player", crash));
|
||||
}
|
||||
|
||||
strcpy(msg, "~g~BLOCKED RECEIVED EVENT~s~\n~b~");
|
||||
strcat(msg, name);
|
||||
strcat(msg, "~s~\nFrom: <C>");
|
||||
strcat(msg, PLAYER::GET_PLAYER_NAME(player));
|
||||
strcat(msg, "</C>");
|
||||
|
||||
above_map(msg);
|
||||
if (auto plyr = g_player_service->get_by_id(player->m_player_id))
|
||||
{
|
||||
session::add_infraction(plyr, Infraction::TRIED_CRASH_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
// Shows a busy spinner till the value at the address equals the value passed or if timeout is hit
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "gta/joaat.hpp"
|
||||
#include "rage/rlSessionByGamerTaskResult.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
|
||||
namespace big::session
|
||||
{
|
||||
@ -89,4 +91,13 @@ namespace big::session
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,11 @@ namespace big
|
||||
NETWORK::NETWORK_BAIL(16, 0, 0);
|
||||
});
|
||||
|
||||
if (g_local_player && g_local_player->m_player_info)
|
||||
{
|
||||
ImGui::InputScalar("Rockstar ID", ImGuiDataType_S64, &g_local_player->m_player_info->m_net_player_data.m_gamer_handle_2.m_rockstar_id, nullptr, nullptr, nullptr, ImGuiInputTextFlags_ReadOnly);
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
152
src/views/network/view_player_database.cpp
Normal file
152
src/views/network/view_player_database.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include "views/view.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "core/data/block_join_reasons.hpp"
|
||||
#include "core/data/infractions.hpp"
|
||||
#include "util/session.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
persistent_player current_player;
|
||||
|
||||
void view::player_database()
|
||||
{
|
||||
static char name_buf[32];
|
||||
static char search[64];
|
||||
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
components::input_text_with_hint("Player", "Search", search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
|
||||
if (ImGui::ListBoxHeader("###players", { 180, static_cast<float>(*g_pointers->m_resolution_y - 400 - 38 * 4) }))
|
||||
{
|
||||
auto& item_arr = g_player_database_service->get_players();
|
||||
if (item_arr.size() > 0)
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (auto& item : item_arr)
|
||||
{
|
||||
auto& player = item.second;
|
||||
|
||||
std::string name = player.name;
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
if (lower_search.empty() || name.find(lower_search) != std::string::npos)
|
||||
{
|
||||
ImGui::PushID(item.first);
|
||||
|
||||
if (components::selectable(player.name, &player == g_player_database_service->get_selected()))
|
||||
{
|
||||
g_player_database_service->set_selected(&player);
|
||||
current_player = player;
|
||||
strncpy(name_buf, current_player.name.data(), sizeof(name_buf));
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("No stored players");
|
||||
}
|
||||
|
||||
ImGui::ListBoxFooter();
|
||||
}
|
||||
|
||||
if (auto selected = g_player_database_service->get_selected())
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::BeginChild("###selected_player", { 500, static_cast<float>(*g_pointers->m_resolution_y - 388 - 38 * 4) }, false, ImGuiWindowFlags_NoBackground))
|
||||
{
|
||||
if (ImGui::InputText("Name", name_buf, sizeof(name_buf)))
|
||||
{
|
||||
current_player.name = name_buf;
|
||||
}
|
||||
|
||||
ImGui::InputScalar("Rockstar ID", ImGuiDataType_S64, ¤t_player.rockstar_id);
|
||||
ImGui::Checkbox("Is Modder", ¤t_player.is_modder);
|
||||
ImGui::Checkbox("Block Join", ¤t_player.block_join);
|
||||
|
||||
if (ImGui::BeginCombo("Block Join Alert", block_join_reasons[current_player.block_join_reason]))
|
||||
{
|
||||
for (const auto& reason : block_join_reasons)
|
||||
{
|
||||
if (ImGui::Selectable(reason.second, reason.first == current_player.block_join_reason))
|
||||
{
|
||||
current_player.block_join_reason = reason.first;
|
||||
}
|
||||
|
||||
if (reason.first == current_player.block_join_reason)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Only works as host");
|
||||
|
||||
|
||||
if (!current_player.infractions.empty())
|
||||
{
|
||||
ImGui::Text("Infractions:");
|
||||
|
||||
for (auto& infraction : current_player.infractions)
|
||||
{
|
||||
ImGui::BulletText(infraction_desc[(Infraction)infraction]);
|
||||
}
|
||||
}
|
||||
|
||||
components::button("Join Session", []
|
||||
{
|
||||
session::join_by_rockstar_id(current_player.rockstar_id);
|
||||
});
|
||||
|
||||
if (ImGui::Button("Save"))
|
||||
{
|
||||
if (current_player.rockstar_id != selected->rockstar_id)
|
||||
g_player_database_service->update_rockstar_id(selected->rockstar_id, current_player.rockstar_id);
|
||||
|
||||
*selected = current_player;
|
||||
g_player_database_service->save();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Remove"))
|
||||
{
|
||||
g_player_database_service->remove_rockstar_id(selected->rockstar_id);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Remove All"))
|
||||
{
|
||||
g_player_database_service->set_selected(nullptr);
|
||||
g_player_database_service->get_players().clear();
|
||||
g_player_database_service->save();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
components::sub_title("New Entry");
|
||||
|
||||
static char new_name[64];
|
||||
static int64_t new_rockstar_id;
|
||||
|
||||
ImGui::InputText("Name", new_name, sizeof(new_name));
|
||||
ImGui::InputScalar("Rockstar ID", ImGuiDataType_S64, &new_rockstar_id);
|
||||
|
||||
if (ImGui::Button("Add"))
|
||||
{
|
||||
g_player_database_service->get_players()[new_rockstar_id] = persistent_player(new_name, new_rockstar_id);
|
||||
g_player_database_service->save();
|
||||
}
|
||||
}
|
||||
}
|
@ -42,6 +42,13 @@ namespace big
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
components::sub_title("Player Magnet");
|
||||
ImGui::Checkbox("Enabled", &g->session.player_magnet_enabled);
|
||||
if (g->session.player_magnet_enabled)
|
||||
{
|
||||
ImGui::InputInt("Player Count", &g->session.player_magnet_count);
|
||||
}
|
||||
|
||||
components::sub_title("Chat");
|
||||
ImGui::Checkbox("Disable Filter", &g->session.disable_chat_filter);
|
||||
ImGui::Checkbox("Log Chat Messages", &g->session.log_chat_messages);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "gta_util.hpp"
|
||||
#include "services/pickups/pickup_service.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "services/player_database/player_database_service.hpp"
|
||||
#include "util/globals.hpp"
|
||||
#include "util/misc.hpp"
|
||||
#include "util/ped.hpp"
|
||||
@ -18,53 +19,6 @@ namespace big
|
||||
|
||||
if (g_player_service->get_selected()->is_valid())
|
||||
{
|
||||
if (ImGui::TreeNode("Misc"))
|
||||
{
|
||||
components::button("Steal Outfit", [] {
|
||||
ped::steal_outfit(
|
||||
PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id())
|
||||
);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Steal Identity", [] {
|
||||
ped::steal_identity(
|
||||
PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id())
|
||||
);
|
||||
});
|
||||
|
||||
components::button("Clear Wanted Level", [] {
|
||||
globals::clear_wanted_player(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Give Armour", [] {
|
||||
g_pickup_service->give_player_armour(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
components::button("Give Ammo", [] {
|
||||
g_pickup_service->give_player_ammo(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Give Weapons", [] {
|
||||
g_pickup_service->give_player_weapons(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Info")) {
|
||||
|
||||
ImGui::Text("Player ID: %d", g_player_service->get_selected()->id());
|
||||
@ -164,6 +118,11 @@ namespace big
|
||||
);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add To Database"))
|
||||
{
|
||||
g_player_database_service->get_or_create_player(g_player_service->get_selected());
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
@ -187,6 +146,60 @@ namespace big
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Misc"))
|
||||
{
|
||||
components::button("Steal Outfit", []
|
||||
{
|
||||
ped::steal_outfit(
|
||||
PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id())
|
||||
);
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Steal Identity", []
|
||||
{
|
||||
ped::steal_identity(
|
||||
PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id())
|
||||
);
|
||||
});
|
||||
|
||||
components::button("Clear Wanted Level", []
|
||||
{
|
||||
globals::clear_wanted_player(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Give Armour", []
|
||||
{
|
||||
g_pickup_service->give_player_armour(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
components::button("Give Ammo", []
|
||||
{
|
||||
g_pickup_service->give_player_ammo(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
components::button("Give Weapons", []
|
||||
{
|
||||
g_pickup_service->give_player_weapons(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,9 @@ namespace big
|
||||
const ImRect icons_box(icons_pos, icons_pos + icons_size);
|
||||
ImGui::PopFont();
|
||||
|
||||
if (plyr->is_modder)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 0.1f, 0.1f, 1.f));
|
||||
|
||||
if (selected_player)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.29f, 0.45f, 0.69f, 1.f));
|
||||
|
||||
@ -53,6 +56,9 @@ namespace big
|
||||
if (selected_player)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (plyr->is_modder)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// render icons on top of the player button
|
||||
ImGui::PushFont(g->window.font_icon);
|
||||
ImGui::RenderTextWrapped(icons_box.Min, player_iconsc, player_icons_end, icons_size.x);
|
||||
|
@ -28,6 +28,7 @@ namespace big
|
||||
static void root();
|
||||
static void self();
|
||||
static void session();
|
||||
static void player_database();
|
||||
static void settings();
|
||||
static void vehicle();
|
||||
static void lsc();
|
||||
|
Reference in New Issue
Block a user