Netsync stuff (#5)

* feat(metric): add rlMetric

* fix(metric): serializer fix

* feat(tls): add tlsContext

* feat(fwEntity): add entity classes

* fix: add import

* fix(vector): constexpr ctors

* feat(ped): add CPed

* feat(sync): add sync nodes

* feat(netsync): add netSyncDataNode::IsActive

* feat(netsync): first node

* fix: make GetData accessible

* fix: make netSyncDataNode an abstract class

* fix(netsync): the compiler is too smart for its own good

* feat(netsync): add CObjectCreationData

* feat(netsync): add CPlayerAppearanceData

* feat(netsync): CVehicleCreationData

* feat(netsync): add CPickupCreationData

* feat(netsync): add CPhysicalAttachData

* feat(netsync): add CVehicleProximityMigrationData

* feat(netsync): add CPedTaskTreeData

* feat(network): add CScriptedGameEvent

---------
This commit is contained in:
maybegreat48 2023-10-09 13:01:36 +00:00 committed by GitHub
parent ca56c5acdd
commit 0132075d1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 487 additions and 4 deletions

View File

@ -3,8 +3,23 @@
#include "base/fwRefAwareBase.hpp" #include "base/fwRefAwareBase.hpp"
#include "base/fwRefAwareBaseImpl.hpp" #include "base/fwRefAwareBaseImpl.hpp"
#include "entity/fwEntity.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/CNetGamePlayer.hpp"
#include "network/CNetworkPlayerMgr.hpp" #include "network/CNetworkPlayerMgr.hpp"
#include "network/CScriptedGameEvent.hpp"
#include "network/netGameEvent.hpp"
#include "network/netObject.hpp" #include "network/netObject.hpp"
#include "network/netPeerAddress.hpp" #include "network/netPeerAddress.hpp"
#include "network/netPlayer.hpp" #include "network/netPlayer.hpp"
@ -15,12 +30,15 @@
#include "player/CPlayerInfo.hpp" #include "player/CPlayerInfo.hpp"
#include "ped/CPed.hpp" #include "ped/CPed.hpp"
#include "rage/atArray.hpp" #include "rage/atArray.hpp"
#include "rage/atPlayerBits.hpp"
#include "rage/joaat.hpp" #include "rage/joaat.hpp"
#include "rage/rlJson.hpp" #include "rage/rlJson.hpp"
#include "rage/rlMetric.hpp" #include "rage/rlMetric.hpp"
#include "rage/tlsContext.hpp" #include "rage/tlsContext.hpp"
#include "rage/vector.hpp" #include "rage/vector.hpp"
#include "script/scriptHandlerNetComponent.hpp" #include "script/scriptHandlerNetComponent.hpp"
#include "script/scriptId.hpp"
#include "script/scriptIdBase.hpp"
#include "script/scrNativeHandler.hpp" #include "script/scrNativeHandler.hpp"
#include "script/scrThread.hpp" #include "script/scrThread.hpp"
#include "script/scrThreadContext.hpp" #include "script/scrThreadContext.hpp"

View File

@ -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);

19
network/netGameEvent.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
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);
}

View File

@ -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<typename T>
T& GetData()
{
return *reinterpret_cast<T*>(&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 {};

View File

@ -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);

View File

@ -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)
}

View File

@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
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)
}

View File

@ -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)
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
// 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);

View File

@ -0,0 +1,15 @@
#pragma once
#include <cstdint>
// 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);

View File

@ -0,0 +1,45 @@
#pragma once
#include <cstdint>
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);

View File

@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
#include "rage/vector.hpp"
#include <cstddef>
#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);

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
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);

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
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);

View File

@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
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);

View File

@ -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<int> m_Velocity; //0x0060
uint32_t m_UnkAmount; //0x006C
}; //Size: 0x0070
static_assert(sizeof(CVehicleProximityMigrationData) == 0x70);
#pragma pack(pop)

31
rage/atPlayerBits.hpp Normal file
View File

@ -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)

View File

@ -9,9 +9,11 @@ namespace rage
#pragma pack(push, 8) #pragma pack(push, 8)
class tlsContext class tlsContext
{ {
char pad[0x1700];
public: public:
bool m_RunningScript; // 0x1700 char pad[0x410]; // 0x0000
int m_SyncThreadIndex; // 0x0410
char pad2[0x12EC]; // 0x0414
bool m_RunningScript; // 0x1700
#if _WIN32 #if _WIN32
static tlsContext* Get() static tlsContext* Get()
@ -22,5 +24,5 @@ namespace rage
#endif #endif
}; };
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(rage::tlsContext) == 0x1701); static_assert(sizeof(rage::tlsContext) == 0x1704);
} }

View File

@ -84,4 +84,4 @@ namespace rage
typedef vector4<float> fvector4; typedef vector4<float> fvector4;
typedef matrix34<float> fmatrix34; typedef matrix34<float> fmatrix34;
typedef matrix44<float> fmatrix44; typedef matrix44<float> fmatrix44;
} }

Binary file not shown.

31
script/scriptId.hpp Normal file
View File

@ -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)

53
script/scriptIdBase.hpp Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <cstdint>
#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)