diff --git a/classes.cpp b/classes.cpp index ac4474c..798f004 100644 --- a/classes.cpp +++ b/classes.cpp @@ -3,8 +3,23 @@ #include "base/fwRefAwareBase.hpp" #include "base/fwRefAwareBaseImpl.hpp" #include "entity/fwEntity.hpp" +#include "network/sync/object/CObjectCreationData.hpp" +#include "network/sync/ped/CPedCreationData.hpp" +#include "network/sync/ped/CPedTaskTreeData.hpp" +#include "network/sync/physical/CPhysicalAttachData.hpp" +#include "network/sync/pickup/CPickupCreationData.hpp" +#include "network/sync/player/CPlayerAppearanceData.hpp" +#include "network/sync/vehicle/CVehicleCreationData.hpp" +#include "network/sync/vehicle/CVehicleProximityMigrationData.hpp" +#include "network/sync/CProjectBaseSyncDataNode.hpp" +#include "network/sync/netSyncDataNode.hpp" +#include "network/sync/netSyncNodeBase.hpp" +#include "network/sync/netSyncTree.hpp" +#include "network/sync/NodeCommonDataOperations.hpp" #include "network/CNetGamePlayer.hpp" #include "network/CNetworkPlayerMgr.hpp" +#include "network/CScriptedGameEvent.hpp" +#include "network/netGameEvent.hpp" #include "network/netObject.hpp" #include "network/netPeerAddress.hpp" #include "network/netPlayer.hpp" @@ -15,12 +30,15 @@ #include "player/CPlayerInfo.hpp" #include "ped/CPed.hpp" #include "rage/atArray.hpp" +#include "rage/atPlayerBits.hpp" #include "rage/joaat.hpp" #include "rage/rlJson.hpp" #include "rage/rlMetric.hpp" #include "rage/tlsContext.hpp" #include "rage/vector.hpp" #include "script/scriptHandlerNetComponent.hpp" +#include "script/scriptId.hpp" +#include "script/scriptIdBase.hpp" #include "script/scrNativeHandler.hpp" #include "script/scrThread.hpp" #include "script/scrThreadContext.hpp" diff --git a/network/CScriptedGameEvent.hpp b/network/CScriptedGameEvent.hpp new file mode 100644 index 0000000..d2c9dc5 --- /dev/null +++ b/network/CScriptedGameEvent.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "netGameEvent.hpp" +#include "script/scriptId.hpp" +#include "rage/atPlayerBits.hpp" + +#pragma pack(push, 8) +class CScriptedGameEvent : public rage::netGameEvent +{ +public: + CGameScriptId m_ScriptId; // 0x38 + int m_DataSize; // 0x60 + bool m_Unk; // 0x64 (netComponent && *(netComponent + 0x16C) == 32) + bool m_ScriptIdOverridden; // 0x65 + bool m_HasScriptMetadataIdx; // 0x66 + std::uint64_t m_Data[54]; // 0x68 + rage::atPlayerBits m_ReceiverBits; // 0x218 + int m_ScriptMetadataIndex; // 0x21C + int m_ScriptHash; // 0x220 + int16_t m_Status; // 0x224 +}; +#pragma pack(pop) +static_assert(sizeof(CScriptedGameEvent) == 0x228); \ No newline at end of file diff --git a/network/netGameEvent.hpp b/network/netGameEvent.hpp new file mode 100644 index 0000000..875b9b5 --- /dev/null +++ b/network/netGameEvent.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +class CNetGamePlayer; +namespace rage +{ + class netGameEvent + { + public: + virtual ~netGameEvent() = 0; // 0x00 + + std::int16_t m_EventType; // 0x08 + bool m_RequiresReply; // 0x0A + char m_Pad1[0xD]; // 0x0B + class CNetGamePlayer* m_Sender; // 0x18 + char m_Pad2[0x18]; // 0x20 + }; + static_assert(sizeof(rage::netGameEvent) == 0x38); +} \ No newline at end of file diff --git a/network/sync/CProjectBaseSyncDataNode.hpp b/network/sync/CProjectBaseSyncDataNode.hpp new file mode 100644 index 0000000..8b5426a --- /dev/null +++ b/network/sync/CProjectBaseSyncDataNode.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "netSyncDataNode.hpp" +#include "NodeCommonDataOperations.hpp" + +namespace rage +{ + class netSyncData; + class netObject; +} + +class CProjectBaseSyncDataNode : public rage::netSyncDataNode +{ +private: + NodeCommonDataOperations m_CommonDataOperations; // 0x120 + char m_Data[]; // 0x130 + +public: +#if _WIN32 + template + T& GetData() + { + return *reinterpret_cast(&m_Data[rage::tlsContext::Get()->m_SyncThreadIndex * sizeof(T)]); + } +#endif +}; +static_assert(sizeof(CProjectBaseSyncDataNode) == 0x130); + +// We probably don't need these anymore +//class CSyncDataNodeFrequent : public CProjectBaseSyncDataNode {}; +//class CSyncDataNodeInfrequent : public CProjectBaseSyncDataNode {}; \ No newline at end of file diff --git a/network/sync/NodeCommonDataOperations.hpp b/network/sync/NodeCommonDataOperations.hpp new file mode 100644 index 0000000..dcb6a7e --- /dev/null +++ b/network/sync/NodeCommonDataOperations.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace rage +{ + class datBitBuffer; +} + +class NodeCommonDataOperations +{ +public: + virtual ~NodeCommonDataOperations() = default; + virtual void ReadFromBuffer(rage::datBitBuffer* buffer, void* log) {}; // 0x08 + virtual void WriteToBuffer(void* data_base, rage::datBitBuffer* buffer, void* log, bool cache) {}; // 0x10 + virtual void Unk() {}; // 0x18 + // TODO: + virtual int CalculateSize(rage::datBitBuffer* buffer) { return 0; }; // 0x20 + virtual int CalculateSize2(rage::datBitBuffer* buffer) { return 0; }; // 0x28 + virtual void LogSyncData(rage::datBitBuffer* buffer) {}; // 0x30 + virtual void LogSyncData2(rage::datBitBuffer* buffer) {}; // 0x38 + rage::datBitBuffer* m_Buffer; // 0x8 +}; +static_assert(sizeof(NodeCommonDataOperations) == 0x10); \ No newline at end of file diff --git a/network/sync/netSyncDataNode.hpp b/network/sync/netSyncDataNode.hpp new file mode 100644 index 0000000..a973e2e --- /dev/null +++ b/network/sync/netSyncDataNode.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "netSyncNodeBase.hpp" +#include "rage/tlsContext.hpp" + +namespace rage +{ +#pragma pack(push, 8) + class netSyncDataNode : public netSyncNodeBase + { + struct ThreadData + { + bool m_Unk; + bool m_NodeActive; + }; + static_assert(sizeof(ThreadData) == 2); + + public: + uint32_t m_Flags; // 0x40 + uint32_t pad3; // 0x44 + uint64_t pad4; // 0x48 + netSyncDataNode* m_ParentData; // 0x50 + uint32_t m_MoreFlags; // 0x58 + netSyncDataNode* m_Children[19]; // 0x60 + ThreadData m_ThreadData[8]; // 0xF8 + char pad5[10]; // 0x110 + void* m_CommonDataOpsVFT; // 0x118 + +#if _WIN32 + inline bool IsActive() + { + return m_ThreadData[rage::tlsContext::Get()->m_SyncThreadIndex].m_NodeActive; + } +#endif + }; + static_assert(sizeof(netSyncDataNode) == 0x120); +#pragma pack(pop) +} \ No newline at end of file diff --git a/network/sync/netSyncNodeBase.hpp b/network/sync/netSyncNodeBase.hpp new file mode 100644 index 0000000..51605c2 --- /dev/null +++ b/network/sync/netSyncNodeBase.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace rage +{ + class datBitBuffer; + class netSyncTree; + +#pragma pack(push, 8) + class netSyncNodeBase + { + public: + virtual ~netSyncNodeBase() = default; // 0x00 + virtual bool IsDataNode() = 0; // 0x08 + virtual bool IsParentNode() = 0; // 0x10 + virtual void MoveCommonDataOpsVFT() = 0; // 0x18 + virtual void ClearChildren() = 0; // 0x20 + virtual void _0x28(void*, void*, void*, int* out_count) = 0; // 0x28 + virtual bool Serialize(int flags, int flags2, void*, rage::datBitBuffer* buffer, int, void*, bool, int*, int* num_serialized) = 0; // 0x30 + virtual bool Deserialize(int flags, int flags2, rage::datBitBuffer* buffer, void*) = 0; // 0x38 + virtual int CalculateSize(int flags, int flags2, void*) = 0; // 0x40 + virtual int CalculateSize2(int flags, int flags2, bool) = 0; // 0x48 + + netSyncNodeBase* m_NextSibling; //0x0008 + netSyncNodeBase* m_PrevSibling; //0x0010 + netSyncTree* m_Root; //0x0018 + netSyncNodeBase* m_Parent; //0x0020 + + uint32_t m_Flags1; //0x0028 + uint32_t m_Flags2; //0x002C + uint32_t m_Flags3; //0x0030 + + uint32_t m_Pad2; //0x0034 + + netSyncNodeBase* m_FirstChild; //0x0038 + }; //Size: 0x0040 + static_assert(sizeof(netSyncNodeBase) == 0x40); +#pragma pack(pop) +} \ No newline at end of file diff --git a/network/sync/netSyncTree.hpp b/network/sync/netSyncTree.hpp new file mode 100644 index 0000000..97f929d --- /dev/null +++ b/network/sync/netSyncTree.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "netSyncNodeBase.hpp" + +namespace rage +{ +#pragma pack(push, 8) + class netSyncTree + { + public: + char pad_0000[176]; //0x0000 + netSyncNodeBase* m_NextSyncNode; //0x00B0 + netSyncNodeBase* m_LastSyncNode; //0x00B8 + uint32_t m_NodeCount; //0x00C0 + uint32_t m_SyncNodeCount; //0x00C4 + char pad_00C8[24]; //0x00C8 + netSyncNodeBase* m_Nodes[74]; //0x00E0 + uint32_t m_NodeMaxCount; //0x0330 + netSyncNodeBase* m_SyncNodes[64]; //0x0338 + uint32_t m_SyncNodeMaxCount; //0x0538 + char pad_053C[900]; //0x053C + }; //Size: 0x08C0 + static_assert(sizeof(rage::netSyncTree) == 0x8C0); +#pragma pack(pop) +} \ No newline at end of file diff --git a/network/sync/object/CObjectCreationData.hpp b/network/sync/object/CObjectCreationData.hpp new file mode 100644 index 0000000..3643237 --- /dev/null +++ b/network/sync/object/CObjectCreationData.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +// TODO +class CObjectCreationData +{ +public: + char pad_0000[284]; //0x0000 + uint32_t m_ObjectType; //0x011C + uint32_t m_ModelHash; //0x0120 + char pad_0124[76]; //0x0124 +}; //Size: 0x0170 +static_assert(sizeof(CObjectCreationData) == 0x170); \ No newline at end of file diff --git a/network/sync/ped/CPedCreationData.hpp b/network/sync/ped/CPedCreationData.hpp new file mode 100644 index 0000000..029dddb --- /dev/null +++ b/network/sync/ped/CPedCreationData.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +// TODO +class CPedCreationData +{ +public: + char pad_0000[4]; //0x0000 + uint32_t m_PopulationType; //0x0004 + uint32_t m_ModelHash; //0x0008 + char pad_000C[18]; //0x000C + bool m_BannedPed; //0x001E + char pad_001F[13]; //0x001F +}; //Size: 0x002C +static_assert(sizeof(CPedCreationData) == 0x2C); \ No newline at end of file diff --git a/network/sync/ped/CPedTaskTreeData.hpp b/network/sync/ped/CPedTaskTreeData.hpp new file mode 100644 index 0000000..d6f43ae --- /dev/null +++ b/network/sync/ped/CPedTaskTreeData.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +class CPedTaskData +{ +public: + uint32_t m_TaskType; //0x0000 + char pad_0004[16]; //0x0004 +}; //Size: 0x0014 +static_assert(sizeof(CPedTaskData) == 0x14); + +class CPedTaskTree +{ +public: + uint32_t m_TreeType; //0x0000 + char pad_0004[4]; //0x0004 unused + uint32_t m_NumTasks; //0x0008 + bool m_SequenceTree; //0x000C + class CPedTaskData m_Tasks[12]; //0x0010 + char pad_0100[16]; //0x0100 unused +}; //Size: 0x0110 +static_assert(sizeof(CPedTaskTree) == 0x110); + +class CPedTaskTreeData +{ +public: + class CPedTaskTree m_Trees[5]; //0x0000 + char pad_0550[4]; //0x0550 unused + uint32_t m_ScriptCommand; //0x0554 + uint32_t m_ScriptTaskStage; //0x0558 + + int GetNumTaskTrees() + { + switch (m_Trees[0].m_TreeType) + { + case 0: return 5; + case 1: return 2; + case 2: return 0; + case 3: return 1; + } + + return 0; + } +}; //Size: 0x055C +static_assert(sizeof(CPedTaskTreeData) == 0x55C); diff --git a/network/sync/physical/CPhysicalAttachData.hpp b/network/sync/physical/CPhysicalAttachData.hpp new file mode 100644 index 0000000..bd01bb5 --- /dev/null +++ b/network/sync/physical/CPhysicalAttachData.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include "rage/vector.hpp" +#include + +#pragma pack(push, 8) +class CPhysicalAttachData +{ +public: + bool m_IsAttached; //0x0000 + uint16_t m_AttachObjectId; //0x0002 + alignas(16) rage::fvector3 m_Offset; //0x0010 + rage::fvector4 m_Orientation; //0x0020 + rage::fvector3 m_ParentOffset; //0x0030 + uint16_t m_OtherAttachBone; //0x0040 + uint16_t m_AttachBone; //0x0042 + uint32_t m_AttachFlags; //0x0044 + char pad_0048[24]; //0x0048 +}; //Size: 0x0060 +#pragma pack(pop) +static_assert(sizeof(CPhysicalAttachData) == 0x60); \ No newline at end of file diff --git a/network/sync/pickup/CPickupCreationData.hpp b/network/sync/pickup/CPickupCreationData.hpp new file mode 100644 index 0000000..19b42f7 --- /dev/null +++ b/network/sync/pickup/CPickupCreationData.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +class CPickupCreationData +{ +public: + char pad_0000[68]; //0x0000 + uint32_t m_PickupHash; //0x0044 + uint32_t m_ModelHash; //0x0048 + char pad_004C[236]; //0x004C +}; //Size: 0x0138 +static_assert(sizeof(CPickupCreationData) == 0x138); \ No newline at end of file diff --git a/network/sync/player/CPlayerAppearanceData.hpp b/network/sync/player/CPlayerAppearanceData.hpp new file mode 100644 index 0000000..e771a02 --- /dev/null +++ b/network/sync/player/CPlayerAppearanceData.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +class CPlayerAppearanceData +{ +public: + char pad_0000[23612]; //0x0000 + uint32_t m_ModelHash; //0x5C3C + char pad_5C40[7]; //0x5C40 + bool m_BannedPlayerModel; //0x5C47 +}; //Size: 0x5C48 +static_assert(sizeof(CPlayerAppearanceData) == 0x5C48); \ No newline at end of file diff --git a/network/sync/vehicle/CVehicleCreationData.hpp b/network/sync/vehicle/CVehicleCreationData.hpp new file mode 100644 index 0000000..d553f55 --- /dev/null +++ b/network/sync/vehicle/CVehicleCreationData.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +class CVehicleCreationData +{ +public: + char pad_0000[4]; //0x0000 + uint32_t m_PopulationType; //0x0004 + char pad_0008[4]; //0x0008 + uint32_t m_ModelHash; //0x000C + char pad_0010[24]; //0x0010 +}; //Size: 0x0028 +static_assert(sizeof(CVehicleCreationData) == 0x28); \ No newline at end of file diff --git a/network/sync/vehicle/CVehicleProximityMigrationData.hpp b/network/sync/vehicle/CVehicleProximityMigrationData.hpp new file mode 100644 index 0000000..e526774 --- /dev/null +++ b/network/sync/vehicle/CVehicleProximityMigrationData.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "rage/vector.hpp" + +#pragma pack(push, 8) +class CVehicleProximityMigrationData +{ +public: + uint32_t m_NumPassengers; //0x0000 + bool m_PassengersActive[17]; //0x0004 + uint16_t m_PassengerObjectIds[17]; //0x0016 + bool m_OverridePopulationType; //0x0038 + uint32_t m_PopulationType; //0x003C + uint32_t m_Flags; //0x0040 + uint32_t m_Timestamp; //0x0044 + bool m_HasPositionData; //0x0048 + alignas(16) rage::fvector3 m_Position; //0x0050 + rage::vector3 m_Velocity; //0x0060 + uint32_t m_UnkAmount; //0x006C +}; //Size: 0x0070 +static_assert(sizeof(CVehicleProximityMigrationData) == 0x70); +#pragma pack(pop) \ No newline at end of file diff --git a/rage/atPlayerBits.hpp b/rage/atPlayerBits.hpp new file mode 100644 index 0000000..f7614bf --- /dev/null +++ b/rage/atPlayerBits.hpp @@ -0,0 +1,31 @@ +#pragma once + +#pragma pack(push, 8) +namespace rage +{ + class atPlayerBits + { + constexpr static int MAX_PLAYERS = 32; + int m_PlayerBits[MAX_PLAYERS / 32]; + + public: + bool IsSet(int id) + { + return _bittest((const long*)&m_PlayerBits[id / 32], id % 32); + } + + void Set(int id) + { + m_PlayerBits[id / 32] |= (1 << (id % 32)); + } + + void Clear(int id) + { + m_PlayerBits[id / 32] &= ~(1 << (id % 32)); + } + + // TODO: bit count, CNetGamePlayer... + }; + static_assert(sizeof(rage::atPlayerBits) == 4); +} +#pragma pack(pop) \ No newline at end of file diff --git a/rage/tlsContext.hpp b/rage/tlsContext.hpp index 1f7293b..95369d1 100644 --- a/rage/tlsContext.hpp +++ b/rage/tlsContext.hpp @@ -9,9 +9,11 @@ namespace rage #pragma pack(push, 8) class tlsContext { - char pad[0x1700]; public: - bool m_RunningScript; // 0x1700 + char pad[0x410]; // 0x0000 + int m_SyncThreadIndex; // 0x0410 + char pad2[0x12EC]; // 0x0414 + bool m_RunningScript; // 0x1700 #if _WIN32 static tlsContext* Get() @@ -22,5 +24,5 @@ namespace rage #endif }; #pragma pack(pop) - static_assert(sizeof(rage::tlsContext) == 0x1701); + static_assert(sizeof(rage::tlsContext) == 0x1704); } \ No newline at end of file diff --git a/rage/vector.hpp b/rage/vector.hpp index 71087ed..7a92b6e 100644 --- a/rage/vector.hpp +++ b/rage/vector.hpp @@ -84,4 +84,4 @@ namespace rage typedef vector4 fvector4; typedef matrix34 fmatrix34; typedef matrix44 fmatrix44; -} \ No newline at end of file +} diff --git a/rdr2.rcnet b/rdr2.rcnet index e44c271..eddc6d2 100644 Binary files a/rdr2.rcnet and b/rdr2.rcnet differ diff --git a/script/scriptId.hpp b/script/scriptId.hpp new file mode 100644 index 0000000..7fe94ec --- /dev/null +++ b/script/scriptId.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "scriptIdBase.hpp" + +#pragma pack(push, 8) +namespace rage +{ + class scriptId : public scriptIdBase + { + public: + joaat_t m_ScriptHash; // 0x08 + }; + static_assert(sizeof(scriptId) == 0x10); +} + +class CGameScriptId : public rage::scriptId +{ +public: + int m_Timestamp; // 0x10 (verify) + int m_ObjectBrainPositionHash; // 0x14 + union + { + int m_PedBrainObjectId; // 0x18 + int m_WorldPointBrainIndex; // 0x18 + int m_FallbackId; // 0x18 + }; + int m_InstanceHash; // 0x1C (derived from brain parameters) + bool m_IsPedBrainScript; // 0x20 +}; + +static_assert(sizeof(CGameScriptId) == 0x28); +#pragma pack(pop) \ No newline at end of file diff --git a/script/scriptIdBase.hpp b/script/scriptIdBase.hpp new file mode 100644 index 0000000..f592b3e --- /dev/null +++ b/script/scriptIdBase.hpp @@ -0,0 +1,53 @@ +#pragma once +#include +#include "../rage/joaat.hpp" + +#pragma pack(push, 8) +namespace rage +{ + class datBitBuffer; + class netLoggingInterface; + class scrThread; + + class scriptIdBase + { + public: + virtual ~scriptIdBase() = default; + + // Assumes the script thread's identity. + virtual void FromThread(scrThread*) {}; + + // Returns whether the hash of the script id is valid. + virtual bool IsValid() { return false; }; + + // Gets the hash of the script id. + virtual joaat_t* GetHash(joaat_t* out) { return 0; }; + + // Gets an unknown value from the script id. + virtual std::uint32_t* GetInstanceHash(std::uint32_t* out) { return 0; }; + + // Serializes the script id from the buffer. + virtual void Deserialize(datBitBuffer* buffer) {}; + + // Serializes the script id to the buffer. + virtual void Serialize(datBitBuffer* buffer) {}; + + // Calculates bitbuffer size. + virtual std::uint32_t CalculateSize() { return 0; }; + + // Calls _0x40 and returns its value added to another value. (packed size?) + virtual std::uint32_t CalculateSize2() { return 0; }; + + // Gets the hash of the script id again. + virtual joaat_t GetHash2() { return 0; } + + // Copies the information of other to this object. + virtual void FromScriptId(scriptIdBase* other) {} + + // Returns whether the other script id is equal. + virtual bool operator==(scriptIdBase*) { return false; }; + + virtual bool SameScriptHash(scriptIdBase*) { return false; }; + }; +} +#pragma pack(pop) \ No newline at end of file