feat: handle net game event (#22)

This commit is contained in:
Mr-X-GTA
2025-03-24 21:23:33 +01:00
committed by GitHub
parent c58e70e236
commit b272f7a291
11 changed files with 291 additions and 28 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ namespace YimMenu::Submenus
teleportGroup->AddItem(std::make_shared<CommandItem>("bringall"_J, "Bring All"));
auto customPlayerTp = std::make_shared<Group>("", 1);
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, "##tpcoord"));
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, ""));
customPlayerTp->AddItem(std::make_shared<CommandItem>("tpplayertocoordall"_J, "Teleport Everyone"));
teleportGroup->AddItem(customPlayerTp);
+1 -1
View File
@@ -119,7 +119,7 @@ namespace YimMenu::Submenus
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tptoplayer"_J, "Teleport To"));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("bring"_J));
auto customPlayerTp = std::make_shared<Group>("", 1);
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, "##tpcoord"));
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, ""));
customPlayerTp->AddItem(std::make_shared<PlayerCommandItem>("tpplayertocoord"_J, "Teleport"));
teleportGroup->AddItem(customPlayerTp);
menu->AddItem(teleportGroup);
+7
View File
@@ -13,6 +13,11 @@ namespace rage
class datBitBuffer;
}
namespace YimMenu
{
class Player;
}
namespace YimMenu::Hooks
{
namespace SwapChain
@@ -45,6 +50,8 @@ namespace YimMenu::Hooks
namespace Network
{
extern void ReceiveNetMessage(void* a1, rage::netConnectionManager* mgr, rage::netEvent* event);
extern void ReceiveEvent(YimMenu::Player& player, uint16_t event_id, uint32_t event_index, uint32_t event_handled_bitset, rage::datBitBuffer& buffer);
extern bool HandleScriptedGameEvent(YimMenu::Player& player, int64_t* args, uint32_t args_size);
}
namespace Window
@@ -0,0 +1,62 @@
#include "core/util/Joaat.hpp"
#include "game/backend/Self.hpp"
#include "game/hooks/Hooks.hpp"
#include "game/pointers/Pointers.hpp"
#include "types/network/CNetGamePlayer.hpp"
#include "types/network/NetEventType.hpp"
#include "types/rage/datBitBuffer.hpp"
namespace YimMenu::Hooks
{
static void SendEventAck(rage::netEventMgr* event_mgr, CNetGamePlayer* source_player, CNetGamePlayer* target_player, uint32_t event_index, uint32_t event_handled_bits)
{
if (source_player->m_PlayerIndex != 255 && !Pointers.EventAck(0x778LL * source_player->m_PlayerIndex + (intptr_t)event_mgr + 0x2C408, target_player, event_index, event_handled_bits))
{
Pointers.SendEventAck(event_mgr, source_player);
Pointers.EventAck((intptr_t)event_mgr + 0x2C408 + 0x778LL * source_player->m_PlayerIndex, target_player, event_index, event_handled_bits);
}
}
static bool HandleNetGameEvent(Player& player, uint16_t event_id, rage::datBitBuffer& buffer)
{
switch (static_cast<NetEventType>(event_id))
{
case NetEventType::WEAPON_DAMAGE_EVENT:
{
uint8_t damage_type = buffer.Read<uint8_t>(2);
uint32_t weapon_type = buffer.Read<uint32_t>(32);
if (weapon_type == "WEAPON_TRANQUILIZER"_J)
{
//player.AddDetection();
return false;
}
break;
}
case NetEventType::SCRIPTED_GAME_EVENT:
{
int64_t args[54]{};
uint32_t args_size = buffer.Read<uint32_t>(32);
if (args_size > sizeof(args))
return false;
buffer.ReadArray(args, 8 * args_size);
if (!Network::HandleScriptedGameEvent(player, args, args_size))
return false;
break;
}
}
return true;
}
void Network::ReceiveEvent(Player& player, uint16_t event_id, uint32_t event_index, uint32_t event_handled_bits, rage::datBitBuffer& buffer)
{
if (!HandleNetGameEvent(player, event_id, buffer))
SendEventAck(*Pointers.NetEventMgr, player.GetHandle(), Self::GetPlayer().GetHandle(), event_index, event_handled_bits);
}
}
@@ -0,0 +1,40 @@
#include "game/backend/Self.hpp"
#include "game/hooks/Hooks.hpp"
#include "game/pointers/Pointers.hpp"
#include "types/script/ScriptEvent.hpp"
namespace YimMenu::Hooks
{
bool Network::HandleScriptedGameEvent(YimMenu::Player& player, int64_t* args, uint32_t args_size)
{
SCRIPT_EVENT* script_event = reinterpret_cast<SCRIPT_EVENT*>(args);
switch (static_cast<ScriptEventIndex>(script_event->GetEventIndex()))
{
case ScriptEventIndex::Bounty:
{
SCRIPT_EVENT_BOUNTY* bounty = static_cast<SCRIPT_EVENT_BOUNTY*>(script_event);
if (args_size != SCRIPT_EVENT_BOUNTY::GetSize())
{
//player.AddDetection();
return false;
}
if (bounty->Target == Self::GetPed().GetHandle())
{
return false;
}
break;
}
case ScriptEventIndex::SendTextLabelSMS:
{
//player.AddDetection();
return true;
}
}
return true;
}
}
@@ -45,6 +45,49 @@ namespace YimMenu::Hooks
}
break;
}
case rage::netMessage::Type::PackedEvents:
{
auto player = Players::GetByMessageId(fr_evt->m_MsgId);
if (!player)
break;
uint32_t count = buffer.Read<uint32_t>(5);
uint32_t buffer_size = buffer.Read<uint32_t>(15);
if (buffer_size > 7296)
buffer_size = 7296;
int remaining = buffer_size;
while (remaining >= 39)
{
int bits_read = buffer.m_BitsRead;
uint16_t event_id = buffer.Read<uint16_t>(7);
uint32_t event_index = buffer.Read<uint32_t>(9);
uint32_t event_handled_bits = buffer.Read<uint32_t>(8);
uint32_t event_data_size = buffer.Read<uint32_t>(15);
if (buffer.Read<bool>(1))
buffer.Read<uint32_t>(16);
char event_data[4096 + 1];
if (event_data_size)
{
buffer.ReadArray(event_data, event_data_size);
}
rage::datBitBuffer event_buffer(event_data, sizeof(event_data), true);
event_buffer.m_MaxBit = event_data_size + 1;
ReceiveEvent(player, event_id, event_index, event_handled_bits, event_buffer);
remaining -= (int)buffer.m_BitsRead - bits_read;
}
break;
}
default:
break;
}
+11
View File
@@ -164,6 +164,17 @@ namespace YimMenu
ReceiveNetMessage = ptr.Add(0xD).Add(1).Rip().As<PVOID>();
});
constexpr auto netEventMgrPtrn = Pattern<"4C 8B 05 ? ? ? ? 44 0F B7 CA">("NetEventMgr");
scanner.Add(netEventMgrPtrn, [this](PointerCalculator ptr) {
NetEventMgr = ptr.Add(3).Rip().As<rage::netEventMgr**>();
});
constexpr auto sendEventAckPtrn = Pattern<"84 C0 75 ? 89 EE 49 8D AD">("SendEventAck");
scanner.Add(sendEventAckPtrn, [this](PointerCalculator ptr) {
EventAck = ptr.Sub(4).Rip().As<Functions::EventAck>();
SendEventAck = ptr.Add(0x13).Add(1).Rip().As<Functions::SendEventAck>();
});
if (!scanner.Scan())
{
LOG(FATAL) << "Some patterns could not be found, unloading.";
+6
View File
@@ -13,6 +13,7 @@ namespace rage
class netSyncTree;
class netObject;
class netConnectionManager;
class netEventMgr;
}
class CPedFactory;
class CNetGamePlayer;
@@ -33,6 +34,8 @@ namespace YimMenu
using QueuePacket = void(*)(rage::netConnectionManager* mgr, int msg_id, void* data, int size, int flags, std::uint16_t* out_seq_id);
using GetNetObjectById = rage::netObject* (*)(uint16_t id);
using RequestControl = void(*)(rage::netObject* object);
using EventAck = bool(*)(uintptr_t data, CNetGamePlayer* target_player, uint32_t event_index, uint32_t event_handled_bitset);
using SendEventAck = void(*)(rage::netEventMgr* event_manager, CNetGamePlayer* source_player);
}
struct PointerData
@@ -69,6 +72,9 @@ namespace YimMenu
Functions::RequestControl RequestControl;
std::uint8_t* SpectatePatch; // used to patch the code that prevents you from spawning network objects when spectating
PVOID ReceiveNetMessage;
rage::netEventMgr** NetEventMgr;
Functions::EventAck EventAck;
Functions::SendEventAck SendEventAck;
};
struct Pointers : PointerData
+92
View File
@@ -0,0 +1,92 @@
#pragma once
enum class NetEventType : uint16_t
{
OBJECT_ID_FREED_EVENT,
OBJECT_ID_REQUEST_EVENT,
ARRAY_DATA_VERIFY_EVENT,
SCRIPT_ARRAY_DATA_VERIFY_EVENT,
REQUEST_CONTROL_EVENT,
GIVE_CONTROL_EVENT,
WEAPON_DAMAGE_EVENT,
REQUEST_PICKUP_EVENT,
REQUEST_MAP_PICKUP_EVENT,
GAME_CLOCK_EVENT,
GAME_WEATHER_EVENT,
RESPAWN_PLAYER_PED_EVENT,
GIVE_WEAPON_EVENT,
REMOVE_WEAPON_EVENT,
REMOVE_ALL_WEAPONS_EVENT,
VEHICLE_COMPONENT_CONTROL_EVENT,
FIRE_EVENT,
EXPLOSION_EVENT,
START_PROJECTILE_EVENT,
UPDATE_PROJECTILE_TARGET_EVENT,
REMOVE_PROJECTILE_ENTITY_EVENT,
BREAK_PROJECTILE_TARGET_LOCK_EVENT,
ALTER_WANTED_LEVEL_EVENT,
CHANGE_RADIO_STATION_EVENT,
RAGDOLL_REQUEST_EVENT,
PLAYER_TAUNT_EVENT,
PLAYER_CARD_STAT_EVENT,
DOOR_BREAK_EVENT,
SCRIPTED_GAME_EVENT,
REMOTE_SCRIPT_INFO_EVENT,
REMOTE_SCRIPT_LEAVE_EVENT,
MARK_AS_NO_LONGER_NEEDED_EVENT,
CONVERT_TO_SCRIPT_ENTITY_EVENT,
SCRIPT_WORLD_STATE_EVENT,
CLEAR_AREA_EVENT,
CLEAR_RECTANGLE_AREA_EVENT,
NETWORK_REQUEST_SYNCED_SCENE_EVENT,
NETWORK_START_SYNCED_SCENE_EVENT,
NETWORK_STOP_SYNCED_SCENE_EVENT,
NETWORK_UPDATE_SYNCED_SCENE_EVENT,
INCIDENT_ENTITY_EVENT,
GIVE_PED_SCRIPTED_TASK_EVENT,
GIVE_PED_SEQUENCE_TASK_EVENT,
NETWORK_CLEAR_PED_TASKS_EVENT,
NETWORK_START_PED_ARREST_EVENT,
NETWORK_START_PED_UNCUFF_EVENT,
NETWORK_SOUND_CAR_HORN_EVENT,
NETWORK_ENTITY_AREA_STATUS_EVENT,
NETWORK_GARAGE_OCCUPIED_STATUS_EVENT,
PED_CONVERSATION_LINE_EVENT,
SCRIPT_ENTITY_STATE_CHANGE_EVENT,
NETWORK_PLAY_SOUND_EVENT,
NETWORK_STOP_SOUND_EVENT,
NETWORK_PLAY_AIRDEFENSE_FIRE_EVENT,
NETWORK_BANK_REQUEST_EVENT,
NETWORK_AUDIO_BARK_EVENT,
REQUEST_DOOR_EVENT,
NETWORK_TRAIN_REPORT_EVENT,
NETWORK_TRAIN_REQUEST_EVENT,
NETWORK_INCREMENT_STAT_EVENT,
MODIFY_VEHICLE_LOCK_WORD_STATE_DATA,
MODIFY_PTFX_WORD_STATE_DATA_SCRIPTED_EVOLVE_EVENT,
REQUEST_PHONE_EXPLOSION_EVENT,
REQUEST_DETACHMENT_EVENT,
KICK_VOTES_EVENT,
GIVE_PICKUP_REWARDS_EVENT,
BLOW_UP_VEHICLE_EVENT,
NETWORK_SPECIAL_FIRE_EQUIPPED_WEAPON,
NETWORK_RESPONDED_TO_THREAT_EVENT,
NETWORK_SHOUT_TARGET_POSITION,
VOICE_DRIVEN_MOUTH_MOVEMENT_FINISHED_EVENT,
PICKUP_DESTROYED_EVENT,
UPDATE_PLAYER_SCARS_EVENT,
NETWORK_CHECK_EXE_SIZE_EVENT,
NETWORK_PTFX_EVENT,
NETWORK_PED_SEEN_DEAD_PED_EVENT,
REMOVE_STICKY_BOMB_EVENT,
NETWORK_CHECK_CODE_CRCS_EVENT,
INFORM_SILENCED_GUNSHOT_EVENT,
PED_PLAY_PAIN_EVENT,
CACHE_PLAYER_HEAD_BLEND_DATA_EVENT,
REMOVE_PED_FROM_PEDGROUP_EVENT,
REPORT_MYSELF_EVENT,
REPORT_CASH_SPAWN_EVENT,
ACTIVATE_VEHICLE_SPECIAL_ABILITY_EVENT,
BLOCK_WEAPON_SELECTION,
NETWORK_CHECK_CATALOG_CRC
};
+1 -4
View File
@@ -1,10 +1,7 @@
#include "ScriptEvent.hpp"
#include "game/gta/Natives.hpp"
void SCRIPT_EVENT::Send()
void SCRIPT_EVENT::SendImpl(int size)
{
auto size = __SizeOfEvent;
__SizeOfEvent = 0;
SCRIPT::_SEND_TU_SCRIPT_EVENT_NEW(1, this, size / sizeof(std::uint64_t), PlayerBits, EventIndex);
__SizeOfEvent = size;
}
+27 -22
View File
@@ -1,18 +1,30 @@
#pragma once
#include "types.hpp"
#define REGISTER_SCRIPT_EVENT(classType, indexType) \
constexpr static auto EVENT_INDEX = ScriptEventIndex::indexType; \
classType() \
{ \
memset(this, 0, sizeof(classType)); EventIndex = static_cast<int>(EVENT_INDEX); \
__SizeOfEvent = sizeof(classType); \
} \
classType(const classType& other) \
{ \
memcpy(this, &other, sizeof(classType)); \
EventIndex = static_cast<int>(EVENT_INDEX); \
__SizeOfEvent = sizeof(classType); \
#define REGISTER_SCRIPT_EVENT(classType, indexType) \
constexpr static auto EVENT_INDEX = ScriptEventIndex::indexType; \
classType() \
{ \
memset(this, 0, sizeof(classType)); \
EventIndex = static_cast<int>(EVENT_INDEX); \
} \
classType(const classType& other) \
{ \
memcpy(this, &other, sizeof(classType)); \
EventIndex = static_cast<int>(EVENT_INDEX); \
} \
static constexpr size_t GetSize() \
{ \
return sizeof(classType); \
} \
inline void Send() \
{ \
SendImpl(GetSize()); \
} \
inline void Send(int player) \
{ \
SetPlayer(player); \
SendImpl(GetSize()); \
}
// I doubt rockstar would cycle this again, but best to keep this, just in case
@@ -71,8 +83,7 @@ struct SCRIPT_EVENT
{
protected:
SCR_HASH EventIndex; // 0x00
Player SenderIndex; // 0x08
int __SizeOfEvent; // 0x0C
PLAYER_INDEX SenderIndex; // 0x08
SCR_INT PlayerBits; // 0x10
public:
@@ -106,14 +117,8 @@ public:
PlayerBits |= (1 << player);
}
// must be called in script context
void Send();
inline void Send(int player)
{
SetPlayer(player);
Send();
}
protected:
void SendImpl(int size);
};
static_assert(sizeof(SCRIPT_EVENT) == 3 * 8);