diff --git a/PrivateMenu.sln b/PrivateMenu.sln
index b81c1b11a7..a1f090f9a8 100644
--- a/PrivateMenu.sln
+++ b/PrivateMenu.sln
@@ -16,28 +16,56 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook\MinHook.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cryptlib", "Cryptopp\src\cryptlib.vcxproj", "{C39F4B46-6E89-4074-902E-CA57073044D2}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classes", "classes\classes.vcxproj", "{64B538A8-E487-477D-A150-38C9A520A5A9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8F281285-54DA-43C6-BAC9-23D3EB65E636}.Debug|x64.ActiveCfg = Release|x64
{8F281285-54DA-43C6-BAC9-23D3EB65E636}.Debug|x64.Build.0 = Release|x64
+ {8F281285-54DA-43C6-BAC9-23D3EB65E636}.Debug|x86.ActiveCfg = Release|x64
+ {8F281285-54DA-43C6-BAC9-23D3EB65E636}.Debug|x86.Build.0 = Release|x64
{8F281285-54DA-43C6-BAC9-23D3EB65E636}.Release|x64.ActiveCfg = Release|x64
{8F281285-54DA-43C6-BAC9-23D3EB65E636}.Release|x64.Build.0 = Release|x64
+ {8F281285-54DA-43C6-BAC9-23D3EB65E636}.Release|x86.ActiveCfg = Release|x64
+ {8F281285-54DA-43C6-BAC9-23D3EB65E636}.Release|x86.Build.0 = Release|x64
{9A8D6D59-23F1-49CB-A556-6E53947FA100}.Debug|x64.ActiveCfg = Debug|x64
{9A8D6D59-23F1-49CB-A556-6E53947FA100}.Debug|x64.Build.0 = Debug|x64
+ {9A8D6D59-23F1-49CB-A556-6E53947FA100}.Debug|x86.ActiveCfg = Debug|x64
+ {9A8D6D59-23F1-49CB-A556-6E53947FA100}.Debug|x86.Build.0 = Debug|x64
{9A8D6D59-23F1-49CB-A556-6E53947FA100}.Release|x64.ActiveCfg = Release|x64
{9A8D6D59-23F1-49CB-A556-6E53947FA100}.Release|x64.Build.0 = Release|x64
+ {9A8D6D59-23F1-49CB-A556-6E53947FA100}.Release|x86.ActiveCfg = Release|x64
+ {9A8D6D59-23F1-49CB-A556-6E53947FA100}.Release|x86.Build.0 = Release|x64
{09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Debug|x64.ActiveCfg = Debug|x64
{09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Debug|x64.Build.0 = Debug|x64
+ {09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Debug|x86.ActiveCfg = Debug|x64
+ {09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Debug|x86.Build.0 = Debug|x64
{09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Release|x64.ActiveCfg = Release|x64
{09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Release|x64.Build.0 = Release|x64
+ {09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Release|x86.ActiveCfg = Release|x64
+ {09699103-49E1-4E94-8EEF-E5FC4F7CFF23}.Release|x86.Build.0 = Release|x64
{C39F4B46-6E89-4074-902E-CA57073044D2}.Debug|x64.ActiveCfg = Debug|x64
{C39F4B46-6E89-4074-902E-CA57073044D2}.Debug|x64.Build.0 = Debug|x64
+ {C39F4B46-6E89-4074-902E-CA57073044D2}.Debug|x86.ActiveCfg = Debug|Win32
+ {C39F4B46-6E89-4074-902E-CA57073044D2}.Debug|x86.Build.0 = Debug|Win32
{C39F4B46-6E89-4074-902E-CA57073044D2}.Release|x64.ActiveCfg = Release|x64
{C39F4B46-6E89-4074-902E-CA57073044D2}.Release|x64.Build.0 = Release|x64
+ {C39F4B46-6E89-4074-902E-CA57073044D2}.Release|x86.ActiveCfg = Release|Win32
+ {C39F4B46-6E89-4074-902E-CA57073044D2}.Release|x86.Build.0 = Release|Win32
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Debug|x64.ActiveCfg = Debug|x64
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Debug|x64.Build.0 = Debug|x64
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Debug|x86.ActiveCfg = Debug|Win32
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Debug|x86.Build.0 = Debug|Win32
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Release|x64.ActiveCfg = Release|x64
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Release|x64.Build.0 = Release|x64
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Release|x86.ActiveCfg = Release|Win32
+ {64B538A8-E487-477D-A150-38C9A520A5A9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/PrivateMenu/PrivateMenu.vcxproj b/PrivateMenu/PrivateMenu.vcxproj
index baf759775b..e9f4b69c9b 100644
--- a/PrivateMenu/PrivateMenu.vcxproj
+++ b/PrivateMenu/PrivateMenu.vcxproj
@@ -48,7 +48,7 @@
true
true
false
- $(ProjectDir)src;$(ProjectDir);%(AdditionalIncludeDirectories)
+ $(ProjectDir)src;$(ProjectDir);$(SolutionDir)classes\src;%(AdditionalIncludeDirectories)
Default
Neither
false
diff --git a/classes/classes.vcxproj b/classes/classes.vcxproj
new file mode 100644
index 0000000000..48afab0ec4
--- /dev/null
+++ b/classes/classes.vcxproj
@@ -0,0 +1,157 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+ 17.0
+ Win32Proj
+ {64b538a8-e487-477d-a150-38c9a520a5a9}
+ classes
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)Build\$(ProjectName)\$(Configuration)\
+ $(SolutionDir)Build\Intermediate\$(ProjectName)\$(Configuration)\
+
+
+ $(SolutionDir)Build\$(ProjectName)\$(Configuration)\
+ $(SolutionDir)Build\Intermediate\$(ProjectName)\$(Configuration)\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ stdafx.h
+ stdcpplatest
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ stdafx.h
+ stdcpplatest
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/classes/classes.vcxproj.filters b/classes/classes.vcxproj.filters
new file mode 100644
index 0000000000..555d1aa9f4
--- /dev/null
+++ b/classes/classes.vcxproj.filters
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/classes/src/base/CBaseModelInfo.hpp b/classes/src/base/CBaseModelInfo.hpp
new file mode 100644
index 0000000000..f5acebd96c
--- /dev/null
+++ b/classes/src/base/CBaseModelInfo.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include
+#include "fwArchetype.hpp"
+
+enum class eModelType : std::uint8_t
+{
+ Invalid,
+ Object,
+ MLO,
+ Time,
+ Weapon,
+ Vehicle,
+ Ped,
+ Destructable,
+ WorldObject = 33,
+ Sprinkler = 35,
+ Unk65 = 65,
+ EmissiveLOD = 67,
+ Plant = 129,
+ LOD = 131,
+ Unk132 = 132,
+ Unk133 = 133,
+ OnlineOnlyPed = 134,
+ Building = 161,
+ Unk193 = 193
+};
+
+#pragma pack(push, 8)
+class CBaseModelInfo : public rage::fwArchetype
+{
+public:
+ char pad_0070[8]; //0x0070
+ uint64_t unk_0078; //0x0078
+ uint64_t unk_0080; //0x0080
+ char pad_0088[8]; //0x0088
+ uint64_t unk_0090; //0x0090
+ char pad_0098[5]; //0x0098
+ eModelType m_model_type; //0x009D
+ char pad_009E[6]; //0x009E
+ uint64_t unk_00A8; //0x00A8
+}; //Size: 0x00B0
+static_assert(sizeof(CBaseModelInfo) == 0xB0);
+#pragma pack(pop)
diff --git a/classes/src/base/CNavigation.hpp b/classes/src/base/CNavigation.hpp
new file mode 100644
index 0000000000..c1c8ae677f
--- /dev/null
+++ b/classes/src/base/CNavigation.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "../rage/vector.hpp"
+#include "phArchetype.hpp"
+
+#pragma pack(push, 1)
+class CNavigation
+{
+public:
+ char pad_0000[16]; //0x0000
+ class rage::phArchetypeDamp* m_damp; //0x0010
+ char pad_0018[8]; //0x0018
+ rage::fmatrix44 m_transformation_matrix;
+
+ rage::fvector3* get_position()
+ {
+ return reinterpret_cast(&m_transformation_matrix.rows[3]);
+ }
+
+ void model_to_world(const rage::fvector3& model_coords, rage::fvector3& world_coords)
+ {
+ world_coords.x = model_coords.x * m_transformation_matrix.data[0][0] + model_coords.y * m_transformation_matrix.data[1][0] + model_coords.z * m_transformation_matrix.data[2][0] + m_transformation_matrix.data[3][0];
+ world_coords.y = model_coords.x * m_transformation_matrix.data[0][1] + model_coords.y * m_transformation_matrix.data[1][1] + model_coords.z * m_transformation_matrix.data[2][1] + m_transformation_matrix.data[3][1];
+ world_coords.z = model_coords.x * m_transformation_matrix.data[0][2] + model_coords.y * m_transformation_matrix.data[1][2] + model_coords.z * m_transformation_matrix.data[2][2] + m_transformation_matrix.data[3][2];
+ }
+}; //Size: 0x0060
+static_assert(sizeof(CNavigation) == 0x60);
+#pragma pack(pop)
diff --git a/classes/src/base/CObject.hpp b/classes/src/base/CObject.hpp
new file mode 100644
index 0000000000..f825a50a6b
--- /dev/null
+++ b/classes/src/base/CObject.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include "../entities/CPhysical.hpp"
+
+class CWeapon;
+
+#pragma pack(push, 2)
+class CObject : public rage::CPhysical
+{
+ char gap30C[60];
+ uint64_t qword348;
+ char gap350[8];
+ uint64_t qword358;
+ uint16_t word360;
+ uint32_t dword362;
+ uint16_t word366;
+ char gap368[120];
+ uint64_t qword3E0;
+ char gap3E8[8];
+ uint64_t qword3F0;
+ uint64_t qword3F8;
+ uint64_t qword400;
+ uint64_t qword408;
+ uint64_t qword410;
+};
+static_assert(sizeof(CObject) == 0x3F8);
+#pragma pack(pop)
diff --git a/classes/src/base/HashTable.hpp b/classes/src/base/HashTable.hpp
new file mode 100644
index 0000000000..93d90168ec
--- /dev/null
+++ b/classes/src/base/HashTable.hpp
@@ -0,0 +1,28 @@
+#pragma once
+#include
+
+#pragma pack(push, 1)
+class HashNode
+{
+public:
+ int32_t m_hash; //0x0000
+ uint16_t m_idx; //0x0004
+ char pad_0006[2]; //0x0006
+ HashNode* m_next; //0x0008
+}; //Size: 0x0010
+static_assert(sizeof(HashNode) == 0x10);
+
+template
+class HashTable
+{
+public:
+ T* m_data; //0x0000
+ uint16_t m_size; //0x0008
+ char pad_000A[14]; //0x000A
+ uint64_t m_item_size; //0x0018
+ char pad_0020[64]; //0x0020
+ HashNode** m_lookup_table; //0x0060
+ uint16_t m_lookup_key; //0x0068
+}; //Size: 0x006A
+// static_assert(sizeof(HashTable) == 0x6A); // compiler gives assert error without telling me what the problem is, the class is correct though.
+#pragma pack(pop)
diff --git a/classes/src/base/atRTTI.hpp b/classes/src/base/atRTTI.hpp
new file mode 100644
index 0000000000..f3e86678a7
--- /dev/null
+++ b/classes/src/base/atRTTI.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#define DEFINE_RAGE_RTTI(className) private:\
+ virtual void* _0x00() = 0;\
+ virtual void* _0x08() = 0;\
+ virtual uint32_t _0x10() = 0;\
+ virtual className* _0x18(void*) = 0;\
+ virtual bool _0x20(void*) = 0;\
+ virtual bool _0x28(void**) = 0;\
+ virtual void destructor() = 0;\
+ public:
\ No newline at end of file
diff --git a/classes/src/base/datBase.hpp b/classes/src/base/datBase.hpp
new file mode 100644
index 0000000000..ebbe82ec73
--- /dev/null
+++ b/classes/src/base/datBase.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace rage
+{
+
+ class datBase
+ {
+ public:
+ virtual ~datBase() = default;
+ }; //Size: 0x0008
+ static_assert(sizeof(datBase) == 0x8);
+
+}
\ No newline at end of file
diff --git a/classes/src/base/fwArchetype.hpp b/classes/src/base/fwArchetype.hpp
new file mode 100644
index 0000000000..33b1fc2b15
--- /dev/null
+++ b/classes/src/base/fwArchetype.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include
+#include "../rage/vector.hpp"
+#include "datBase.hpp"
+#include "fwArchetypeDef.hpp"
+
+namespace rage {
+ #pragma pack(push,8)
+ class fwArchetype : public datBase
+ {
+ public:
+ virtual void Initialize() = 0;
+ virtual void InitializeFromArchetypeDef(uint32_t mapTypeStoreIdx, fwArchetypeDef* archetypeDef, bool) = 0;
+ virtual class fwEntity* CreateEntity() = 0;
+
+ char pad_0008[16]; //0x0008
+ int32_t m_hash; //0x0018
+ char unk_001C[4]; //0x001C
+ fvector3 m_bounding_sphere_center; //0x0020
+ float m_bounding_sphere_radius; //0x002C
+ fvector3 m_aabbMin; //0x0030
+ float m_lod_dist; //0x003C
+ fvector3 m_aabbMax; //0x0040
+ float m_hd_texture_dist; //0x004C
+ uint32_t m_flags; //0x0050
+ char unk_0054[4]; //0x0054
+ uint64_t unk_0058; //0x0058
+ char unk_0060[4]; //0x0060
+ uint32_t m_asset_index; //0x0064
+ uint16_t unk_0068; //0x0068
+ uint16_t unk_006A; //0x006A
+ };
+ static_assert(sizeof(fwArchetype) == 0x70);
+ #pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/base/fwArchetypeDef.hpp b/classes/src/base/fwArchetypeDef.hpp
new file mode 100644
index 0000000000..ee5d052a3a
--- /dev/null
+++ b/classes/src/base/fwArchetypeDef.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include
+#include "../rage/vector.hpp"
+
+namespace rage {
+#pragma pack(push,8)
+ class fwArchetypeDef
+ {
+ public:
+ virtual ~fwArchetypeDef() = 0;
+ virtual int GetTypeIdentifier() = 0;
+
+ float m_lod_dist; //0x0008
+ uint32_t m_flags; //0x000C
+ uint32_t m_special_attribute; //0x0010
+ char pad_0014[12]; //0x0014
+ fvector4 m_bounding_box_min; //0x0020
+ fvector4 m_bounding_box_max; //0x0030
+ fvector4 m_bounding_sphere_center; //0x0040
+ float m_bounding_sphere_radius; //0x0050
+ float m_hd_texture_dist; //0x0054
+ uint32_t m_name_hash; //0x0058
+ uint32_t m_texture_dictionary; //0x005C
+ uint32_t m_clip_dictionary_hash; //0x0060
+ uint32_t m_drawable_dictionary_hash; //0x0064
+ uint32_t m_physics_dictionary_hash; //0x0068
+ enum eAssetType : uint32_t
+ {
+ ASSET_TYPE_UNINITIALIZED = 0,
+ ASSET_TYPE_FRAGMENT = 1,
+ ASSET_TYPE_DRAWABLE = 2,
+ ASSET_TYPE_DRAWABLEDICTIONARY = 3,
+ ASSET_TYPE_ASSETLESS = 4,
+ } m_asset_type; //0x006C
+ uint32_t m_asset_name_hash; //0x0070
+ uint64_t *m_extensions; //0x0078
+ uint16_t unk_0080; //0x0080
+ char pad_0082[12]; //0x0082
+ }; //Size: 0x0090
+ static_assert(sizeof(fwArchetypeDef) == 0x90);
+#pragma pack(pop)
+}
diff --git a/classes/src/base/fwExtensibleBase.hpp b/classes/src/base/fwExtensibleBase.hpp
new file mode 100644
index 0000000000..56d5ed24de
--- /dev/null
+++ b/classes/src/base/fwExtensibleBase.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include
+
+#include "fwRefAwareBase.hpp"
+#include "fwExtensionContainer.hpp"
+
+#include "../rage/joaat.hpp"
+
+namespace rage
+{
+ class fwExtensibleBase : public fwRefAwareBase
+ {
+ public:
+ // virtual bool is_of_type(std::uint32_t hash) = 0;
+ // virtual uint32_t const &get_type() = 0;
+
+ fwExtensionContainer* m_extension_container; // 0x0010
+ void *m_extensible_unk; // 0x0018
+ }; //Size: 0x0020
+ static_assert(sizeof(fwExtensibleBase) == 0x20);
+
+}
diff --git a/classes/src/base/fwExtension.hpp b/classes/src/base/fwExtension.hpp
new file mode 100644
index 0000000000..4fe5c79cf6
--- /dev/null
+++ b/classes/src/base/fwExtension.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include
+
+namespace rage
+{
+
+ class fwExtension
+ {
+ public:
+ virtual ~fwExtension() = default;
+ virtual void unk_0x08() = 0;
+ virtual void unk_0x10() = 0;
+ virtual uint32_t get_id() = 0;
+ }; //Size: 0x0008
+ static_assert(sizeof(fwExtension) == 0x8);
+
+}
\ No newline at end of file
diff --git a/classes/src/base/fwExtensionContainer.hpp b/classes/src/base/fwExtensionContainer.hpp
new file mode 100644
index 0000000000..7d31bfe6a4
--- /dev/null
+++ b/classes/src/base/fwExtensionContainer.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "fwExtension.hpp"
+
+namespace rage
+{
+
+ class fwExtensionContainer
+ {
+ public:
+ fwExtension *m_entry; //0x0000
+ fwExtensionContainer* m_next; //0x0008
+ }; //Size: 0x0010
+ static_assert(sizeof(fwExtensionContainer) == 0x10);
+
+}
\ No newline at end of file
diff --git a/classes/src/base/fwRefAwareBase.hpp b/classes/src/base/fwRefAwareBase.hpp
new file mode 100644
index 0000000000..662646e296
--- /dev/null
+++ b/classes/src/base/fwRefAwareBase.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "datBase.hpp"
+#include "fwRefAwareBaseImpl.hpp"
+
+namespace rage
+{
+
+ class fwRefAwareBase : public fwRefAwareBaseImpl
+ {
+ };
+ static_assert(sizeof(fwRefAwareBase) == 0x10);
+
+}
\ No newline at end of file
diff --git a/classes/src/base/fwRefAwareBaseImpl.hpp b/classes/src/base/fwRefAwareBaseImpl.hpp
new file mode 100644
index 0000000000..89987eb05a
--- /dev/null
+++ b/classes/src/base/fwRefAwareBaseImpl.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace rage
+{
+
+ template
+ class fwRefAwareBaseImpl : public T
+ {
+ private:
+ void *m_ref; // 0x08
+ };
+
+}
\ No newline at end of file
diff --git a/classes/src/base/pgBase.hpp b/classes/src/base/pgBase.hpp
new file mode 100644
index 0000000000..25dde4ebe9
--- /dev/null
+++ b/classes/src/base/pgBase.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+namespace rage
+{
+
+ class pgBase
+ {
+ public:
+ virtual ~pgBase() = default;
+ virtual int return_zero() = 0;
+ virtual void error() = 0;
+
+ void *unk_0000; // 0x0000
+ }; //Size: 0x0008
+ static_assert(sizeof(pgBase) == 0x10);
+
+ class pgBaseMetaDataType
+ {
+ public:
+ virtual ~pgBaseMetaDataType() = default;
+ virtual void Lookup(uint32_t hash) = 0;
+ }; //Size: 0x0008
+
+ class pgBaseMetaDataDebugNameType : public pgBaseMetaDataType
+ {
+ public:
+ virtual ~pgBaseMetaDataDebugNameType() = default;
+ char pad_0000[64];
+ }; //Size: 0x0072
+
+ class pgBaseRefCounted : public pgBase
+ {
+ public:
+ virtual ~pgBaseRefCounted() = default;
+ }; //Size: 0x0008
+}
\ No newline at end of file
diff --git a/classes/src/base/pgDictionary.hpp b/classes/src/base/pgDictionary.hpp
new file mode 100644
index 0000000000..248801240e
--- /dev/null
+++ b/classes/src/base/pgDictionary.hpp
@@ -0,0 +1,87 @@
+#pragma once
+
+namespace rage
+{
+ class pgDictionaryBase
+ {
+ public:
+ virtual ~pgDictionaryBase() = default;
+ }; //Size: 0x0008
+
+ template
+ class pgDictionary : public pgDictionaryBase
+ {
+ private:
+ struct Node {
+ T key;
+ Node* next;
+
+ Node(const T& k, Node* n = nullptr)
+ : key(k), next(n) {}
+ };
+ Node* head;
+ public:
+ pgDictionary() : head(nullptr) {}
+ ~pgDictionary() {
+ clearDict();
+ }
+
+ void addDict(const T& key) {
+ Node* newNode = new Node(key, head);
+ head = newNode;
+ }
+
+ bool containsDict(const T& key) const {
+ Node* current = head;
+ while (current != nullptr) {
+ if (current->key == key) {
+ return true;
+ }
+ current = current->next;
+ }
+ return false;
+ }
+
+ void removeDict(const T& key) {
+ if (head == nullptr) {
+ return;
+ }
+
+ if (head->key == key) {
+ Node* temp = head;
+ head = head->next;
+ delete temp;
+ return;
+ }
+
+ Node* current = head;
+ while (current->next != nullptr) {
+ if (current->next->key == key) {
+ Node* temp = current->next;
+ current->next = current->next->next;
+ delete temp;
+ return;
+ }
+ current = current->next;
+ }
+ }
+
+ size_t sizeDict() const {
+ size_t count = 0;
+ Node* current = head;
+ while (current != nullptr) {
+ count++;
+ current = current->next;
+ }
+ return count;
+ }
+
+ void clearDict() {
+ while (head != nullptr) {
+ Node* temp = head;
+ head = head->next;
+ delete temp;
+ }
+ }
+ };
+}
\ No newline at end of file
diff --git a/classes/src/base/phArchetype.hpp b/classes/src/base/phArchetype.hpp
new file mode 100644
index 0000000000..a0186b4a69
--- /dev/null
+++ b/classes/src/base/phArchetype.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "phBound.hpp"
+
+namespace rage
+{
+ class phArchetype
+ {
+ public:
+ char pad_0000[32]; //0x0000
+ class phBound* m_bound; //0x0020
+ char pad_0028[16]; //0x0028
+ }; //Size: 0x0038
+ static_assert(sizeof(phArchetype) == 0x38);
+
+ class phArchetypePhys : public phArchetype
+ {
+ public:
+ char pad_0038[28]; //0x0028
+ float m_water_collision; //0x0054
+ char pad_0058[40]; //0x0058
+ }; //Size: 0x0080
+ static_assert(sizeof(phArchetypePhys) == 0x80);
+
+ class phArchetypeDamp : public phArchetypePhys
+ {
+ public:
+ char pad_0080[96]; //0x0080
+ }; //Size: 0x00E0
+ static_assert(sizeof(phArchetypeDamp) == 0xE0);
+}
\ No newline at end of file
diff --git a/classes/src/base/phBound.hpp b/classes/src/base/phBound.hpp
new file mode 100644
index 0000000000..b3a8d01f4c
--- /dev/null
+++ b/classes/src/base/phBound.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include
+#include "pgBase.hpp"
+#include "../rage/vector.hpp"
+
+namespace rage {
+ class phBoundBase : public pgBase
+ {
+ };
+
+enum class eBoundType : uint8_t
+{
+ SPHERE,
+ CAPSULE,
+ BOX = 3,
+ GEOMETRY,
+ BVH = 8,
+ COMPOSITE = 10,
+ DISC = 12,
+ CYLINDER,
+ PLANE = 15
+};
+
+#pragma pack(push,4)
+ class phBound : public phBoundBase {
+ public:
+ eBoundType m_type; //0x0010
+ uint8_t m_flags; //0x0011
+ uint16_t m_part_index; //0x0012
+ float m_radius_around_centroid; //0x0014
+ char pad_0018[8]; //0x0018
+ fvector4 m_bounding_box_max_xyz_margin_w; //0x0020
+ fvector4 m_bounding_box_min_xyz_ref_count_w; //0x0030
+ fvector4 m_centroid_offset_xyz_material_id_0_w; //0x0040
+ fvector4 m_cg_offset_xyz_material_id_1_w; //0x0050
+ fvector4 m_volume_distribution; //0x0060
+ }; //Size: 0x0070
+ static_assert(sizeof(phBound) == 0x70);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/base/phBoundCapsule.hpp b/classes/src/base/phBoundCapsule.hpp
new file mode 100644
index 0000000000..3346637606
--- /dev/null
+++ b/classes/src/base/phBoundCapsule.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "phBound.hpp"
+
+namespace rage
+{
+#pragma pack(push,1)
+ class phBoundCapsule : public phBound
+ {
+ public:
+ float m_capsule_half_height;
+ uint64_t unk_0074;
+ uint32_t unk_007C;
+ }; //Size: 0x0080
+ static_assert(sizeof(phBoundCapsule) == 0x80);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/base/phBoundComposite.hpp b/classes/src/base/phBoundComposite.hpp
new file mode 100644
index 0000000000..dc73bc9278
--- /dev/null
+++ b/classes/src/base/phBoundComposite.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+#include "phBound.hpp"
+#include "../rage/vector.hpp"
+
+namespace rage
+{
+#pragma pack(push,8)
+ class phBoundComposite : public phBound
+ {
+ public:
+ class phBound** m_bounds; //0x0070
+ fmatrix34* m_current_matrices; //0x0078
+ fmatrix34* m_last_matrices; //0x0080
+ fvector3* unk_0088; //0x0088
+ uint32_t* m_type_and_include_flags; //0x0090
+ uint32_t* m_owned_type_and_include_flags; //0x0098
+ uint16_t m_max_num_bounds; //0x00A0
+ uint16_t m_num_bounds; //0x00A2
+ char pad_00A4[4]; //0x00A4
+ void* unk_00A8; //0x00A8
+ }; //Size: 0x00B0
+ static_assert(sizeof(phBoundComposite) == 0xB0);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/camera/CCameraAngles.hpp b/classes/src/camera/CCameraAngles.hpp
new file mode 100644
index 0000000000..2a57e6f283
--- /dev/null
+++ b/classes/src/camera/CCameraAngles.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "../player/CPlayerAngles.hpp"
+
+class CCameraAngles
+{
+public:
+ char pad_0000[960]; //0x0000
+ CPlayerAngles* angles; //0x03C0
+ char pad_03C8[60]; //0x03C8
+}; //Size: 0x0408
+static_assert(sizeof(CCameraAngles) == 0x408);
diff --git a/classes/src/camera/CCameraManagerAngles.hpp b/classes/src/camera/CCameraManagerAngles.hpp
new file mode 100644
index 0000000000..88c8df1ca8
--- /dev/null
+++ b/classes/src/camera/CCameraManagerAngles.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "CCameraAngles.hpp"
+
+class CCameraManagerAngles
+{
+public:
+ CCameraAngles* m_angles; //0x0000
+}; //Size: 0x0008
+static_assert(sizeof(CCameraManagerAngles) == 0x8);
diff --git a/classes/src/camera/CGameCameraAngles.hpp b/classes/src/camera/CGameCameraAngles.hpp
new file mode 100644
index 0000000000..141448de03
--- /dev/null
+++ b/classes/src/camera/CGameCameraAngles.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "CCameraManagerAngles.hpp"
+
+class CGameCameraAngles
+{
+public:
+ CCameraManagerAngles* m_angles; //0x0000
+ char pad_0008[56]; //0x0008
+}; //Size: 0x0040
+static_assert(sizeof(CGameCameraAngles) == 0x40);
diff --git a/classes/src/classes.cpp b/classes/src/classes.cpp
new file mode 100644
index 0000000000..f4bfba96b6
--- /dev/null
+++ b/classes/src/classes.cpp
@@ -0,0 +1,217 @@
+#include "base/atRTTI.hpp"
+#include "base/CBaseModelInfo.hpp"
+#include "base/CNavigation.hpp"
+#include "base/CObject.hpp"
+#include "base/datBase.hpp"
+#include "base/fwArchetype.hpp"
+#include "base/fwArchetypeDef.hpp"
+#include "base/fwExtensibleBase.hpp"
+#include "base/fwExtension.hpp"
+#include "base/fwExtensionContainer.hpp"
+#include "base/fwRefAwareBase.hpp"
+#include "base/fwRefAwareBaseImpl.hpp"
+#include "base/HashTable.hpp"
+#include "base/pgBase.hpp"
+#include "base/phArchetype.hpp"
+#include "base/phBound.hpp"
+#include "base/phBoundCapsule.hpp"
+#include "base/phBoundComposite.hpp"
+#include "base/pgDictionary.hpp"
+#include "camera/CCameraAngles.hpp"
+#include "camera/CCameraManagerAngles.hpp"
+#include "camera/CGameCameraAngles.hpp"
+#include "draw_handlers/CEntityDrawHandler.hpp"
+#include "draw_handlers/CObjectDrawHandler.hpp"
+#include "draw_handlers/CPedDrawHandler.hpp"
+#include "draw_handlers/CVehicleDrawHandler.hpp"
+#include "draw_handlers/fwDrawData.hpp"
+#include "entities/CAttackers.hpp"
+#include "entities/CDynamicEntity.hpp"
+#include "entities/CEntity.hpp"
+#include "entities/CPhysical.hpp"
+#include "entities/fwEntity.hpp"
+#include "enums/eExplosionTag.hpp"
+#include "enums/eHandlingType.hpp"
+#include "game_files/CGameConfig.hpp"
+#include "misc/CTunables.hpp"
+#include "misc/vfx/TimecycleKeyframeData.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "netsync/CProjectSyncTree.hpp"
+#include "netsync/netSyncDataNode.hpp"
+#include "netsync/netSyncNodeBase.hpp"
+#include "netsync/netSyncParentNode.hpp"
+#include "netsync/netSyncTree.hpp"
+#include "netsync/NodeCommonDataOperations.hpp"
+#include "netsync/nodes/automobile/CAutomobileCreationNode.hpp"
+#include "netsync/nodes/CPedComponents.hpp"
+#include "netsync/nodes/door/CDoorCreationDataNode.hpp"
+#include "netsync/nodes/door/CDoorMovementDataNode.hpp"
+#include "netsync/nodes/door/CDoorScriptGameStateDataNode.hpp"
+#include "netsync/nodes/door/CDoorScriptInfoDataNode.hpp"
+#include "netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp"
+#include "netsync/nodes/entity/CEntityOrientationDataNode.hpp"
+#include "netsync/nodes/entity/CEntityScriptGameStateDataNode.hpp"
+#include "netsync/nodes/entity/CEntityScriptInfoDataNode.hpp"
+#include "netsync/nodes/heli/CHeliHealthDataNode.hpp"
+#include "netsync/nodes/heli/CHeliControlDataNode.hpp"
+#include "netsync/nodes/object/CObjectCreationDataNode.hpp"
+#include "netsync/nodes/ped/CPedAIDataNode.hpp"
+#include "netsync/nodes/ped/CPedAppearanceDataNode.hpp"
+#include "netsync/nodes/ped/CPedAttachDataNode.hpp"
+#include "netsync/nodes/ped/CPedComponentReservationDataNode.hpp"
+#include "netsync/nodes/ped/CPedCreationDataNode.hpp"
+#include "netsync/nodes/ped/CPedGameStateDataNode.hpp"
+#include "netsync/nodes/ped/CPedHealthDataNode.hpp"
+#include "netsync/nodes/ped/CPedInventoryDataNode.hpp"
+#include "netsync/nodes/ped/CPedMovementDataNode.hpp"
+#include "netsync/nodes/ped/CPedMovementGroupDataNode.hpp"
+#include "netsync/nodes/ped/CPedOrientationDataNode.hpp"
+#include "netsync/nodes/ped/CPedScriptCreationDataNode.hpp"
+#include "netsync/nodes/ped/CPedTaskSequenceDataNode.hpp"
+#include "netsync/nodes/ped/CPedTaskSpecificDataNode.hpp"
+#include "netsync/nodes/ped/CPedTaskTreeDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalAngVelocityDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalAttachDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalGameStateDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalHealthDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalMigrationDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalScriptMigrationDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalVelocityDataNode.hpp"
+#include "netsync/nodes/pickup/CPickupCreationDataNode.hpp"
+#include "netsync/nodes/pickup_placement/CPickupPlacementCreationDataNode.hpp"
+#include "netsync/nodes/player/CPlayerAmbientModelStreamingNode.hpp"
+#include "netsync/nodes/player/CPlayerAppearanceDataNode.hpp"
+#include "netsync/nodes/player/CPlayerCameraDataNode.hpp"
+#include "netsync/nodes/player/CPlayerCreationDataNode.hpp"
+#include "netsync/nodes/player/CPlayerGamerDataNode.hpp"
+#include "netsync/nodes/player/CPlayerGameStateDataNode.hpp"
+#include "netsync/nodes/player/CPlayerPedGroupDataNode.hpp"
+#include "netsync/nodes/player/CPlayerSectorPosNode.hpp"
+#include "netsync/nodes/player/CPlayerWantedAndLOSDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CMigrationDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CSectorDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CSectorPositionDataNode.hpp"
+#include "netsync/nodes/task/ClonedTakeOffPedVariationInfo.hpp"
+#include "netsync/nodes/train/CTrainGameStateDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleCreationDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleControlDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleTaskDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleGadgetDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleProximityMigrationDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleComponentReservationDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleDamageStatusDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleSteeringDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleHealthDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleGameStateDataNode.hpp"
+#include "netsync/trees/CDynamicEntitySyncTreeBase.hpp"
+#include "netsync/trees/CEntitySyncTreeBase.hpp"
+#include "netsync/trees/CPhysicalSyncTreeBase.hpp"
+#include "netsync/trees/CProximityMigrateableSyncTreeBase.hpp"
+#include "network/CCommunications.hpp"
+#include "network/ChatData.hpp"
+#include "network/CJoinRequestContext.hpp"
+#include "network/ClanData.hpp"
+#include "network/CMsgJoinResponse.hpp"
+#include "network/CMsgTextMessage.hpp"
+#include "network/CNetComplaintMgr.hpp"
+#include "network/CNetGamePlayer.hpp"
+#include "network/CNetGamePlayerDataMsg.hpp"
+#include "network/CNetworkPlayerMgr.hpp"
+#include "network/netObject.hpp"
+#include "network/netPeerAddress.hpp"
+#include "network/netPlayer.hpp"
+#include "network/netPlayerMgrBase.hpp"
+#include "network/netTime.hpp"
+#include "network/Network.hpp"
+#include "network/RemoteGamerInfoMsg.hpp"
+#include "network/snConnectToPeerTask.hpp"
+#include "network/snSession.hpp"
+#include "network/netConnection.hpp"
+#include "ped/CPed.hpp"
+#include "ped/CPedBoneInfo.hpp"
+#include "ped/CPedFactory.hpp"
+#include "ped/CPedIntelligence.hpp"
+#include "ped/CPedInventory.hpp"
+#include "ped/CPedModelInfo.hpp"
+#include "ped/CPedWeaponManager.hpp"
+#include "player/CNonPhysicalPlayerData.hpp"
+#include "player/CPlayerAngles.hpp"
+#include "player/CPlayerInfo.hpp"
+#include "rage/atArray.hpp"
+#include "rage/atReferenceCounter.hpp"
+#include "rage/atSingleton.hpp"
+#include "rage/joaat.hpp"
+#include "rage/rlGamerHandle.hpp"
+#include "rage/rlGamerInfo.hpp"
+#include "rage/rlGamerInfoBase.hpp"
+#include "rage/rlMetric.hpp"
+#include "rage/rlQueryPresenceAttributesContext.hpp"
+#include "rage/rlScHandle.hpp"
+#include "rage/rlSessionByGamerTaskResult.hpp"
+#include "rage/rlSessionInfo.hpp"
+#include "rage/rlTaskStatus.hpp"
+#include "rage/sysMemAllocator.hpp"
+#include "rage/vector.hpp"
+#include "script/dataList.hpp"
+#include "script/globals/GlobalPlayerBD.hpp"
+#include "script/globals/GPBD_FM.hpp"
+#include "script/globals/GPBD_FM_3.hpp"
+#include "script/globals/GPBD_Kicking.hpp"
+#include "script/globals/GPBD_MissionName.hpp"
+#include "script/globals/GSBD.hpp"
+#include "script/globals/GSBD_BlockB.hpp"
+#include "script/globals/GSBD_FM.hpp"
+#include "script/globals/GSBD_Kicking.hpp"
+#include "script/globals/GSBD_PropertyInstances.hpp"
+#include "script/globals/g_AMC_playerBD.hpp"
+#include "script/CGameScriptObjInfo.hpp"
+#include "script/GtaThread.hpp"
+#include "script/HudColor.hpp"
+#include "script/MPScriptData.hpp"
+#include "script/scriptHandler.hpp"
+#include "script/scriptHandlerMgr.hpp"
+#include "script/scriptHandlerNetComponent.hpp"
+#include "script/scriptId.hpp"
+#include "script/scriptIdBase.hpp"
+#include "script/scriptResource.hpp"
+#include "script/scrNativeHandler.hpp"
+#include "script/scrNativeRegistration.hpp"
+#include "script/scrNativeRegistrationTable.hpp"
+#include "script/scrProgram.hpp"
+#include "script/scrProgramTable.hpp"
+#include "script/scrProgramTableEntry.hpp"
+#include "script/scrThread.hpp"
+#include "script/scrThreadContext.hpp"
+#include "script/scrVector.hpp"
+#include "script/Timer.hpp"
+#include "script/tlsContext.hpp"
+#include "script/types.hpp"
+#include "security/ObfVar.hpp"
+#include "security/RageSecurity.hpp"
+#include "socialclub/FriendInfo.hpp"
+#include "socialclub/FriendRegistry.hpp"
+#include "socialclub/ScInfo.hpp"
+#include "stats/CPlayerCardStats.hpp"
+#include "stats/CStatsSerializationContext.hpp"
+#include "vehicle/CAdvancedData.hpp"
+#include "vehicle/CBaseSubHandlingData.hpp"
+#include "vehicle/CCarHandlingData.hpp"
+#include "vehicle/CHandlingData.hpp"
+#include "vehicle/CHandlingObject.hpp"
+#include "vehicle/CVehicle.hpp"
+#include "vehicle/CVehicleModelInfo.hpp"
+#include "vehicle/CVehicleDriveByMetadataMgr.hpp"
+#include "vehicle/CVehicleSeatMetadataMgr.hpp"
+#include "vehicle/CTrainConfig.hpp"
+#include "vehicle/CGetPedSeatReturnClass.hpp"
+#include "weapon/CAmmoInfo.hpp"
+#include "weapon/CAmmoProjectileInfo.hpp"
+#include "weapon/CAmmoRocketInfo.hpp"
+#include "weapon/CAmmoThrownInfo.hpp"
+#include "weapon/CHomingRocketParams.hpp"
+#include "weapon/CItemInfo.hpp"
+#include "weapon/CWeaponBoneId.hpp"
+#include "weapon/CWeaponInfo.hpp"
+#include "ui/CBlipList.hpp"
diff --git a/classes/src/draw_handlers/CEntityDrawHandler.hpp b/classes/src/draw_handlers/CEntityDrawHandler.hpp
new file mode 100644
index 0000000000..a586b8214e
--- /dev/null
+++ b/classes/src/draw_handlers/CEntityDrawHandler.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "fwDrawData.hpp"
+
+namespace rage
+{
+ class CEntityDrawHandler : public rage::fwDrawData
+ {
+ public:
+
+ };
+ static_assert(sizeof(CEntityDrawHandler) == 0x2C);
+}
diff --git a/classes/src/draw_handlers/CObjectDrawHandler.hpp b/classes/src/draw_handlers/CObjectDrawHandler.hpp
new file mode 100644
index 0000000000..0edb8f9f58
--- /dev/null
+++ b/classes/src/draw_handlers/CObjectDrawHandler.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "CEntityDrawHandler.hpp"
+
+namespace rage
+{
+ class CObjectFragmentDrawHandler : public CEntityDrawHandler
+ {
+ };
+ static_assert(sizeof(CObjectFragmentDrawHandler) == 0x2C);
+}
diff --git a/classes/src/draw_handlers/CPedDrawHandler.hpp b/classes/src/draw_handlers/CPedDrawHandler.hpp
new file mode 100644
index 0000000000..02ebcbf9af
--- /dev/null
+++ b/classes/src/draw_handlers/CPedDrawHandler.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include
+
+#include "CEntityDrawHandler.hpp"
+
+namespace rage
+{
+#pragma pack(push, 4)
+ class CPedDrawHandler : public CEntityDrawHandler
+ {
+ public:
+ uint64_t qword30;
+ uint64_t qword38;
+ char gap40[752];
+ uint32_t dword330;
+ };
+ static_assert(sizeof(CPedDrawHandler) == 0x330);
+#pragma pack(pop)
+}
diff --git a/classes/src/draw_handlers/CVehicleDrawHandler.hpp b/classes/src/draw_handlers/CVehicleDrawHandler.hpp
new file mode 100644
index 0000000000..d4ccc9e07e
--- /dev/null
+++ b/classes/src/draw_handlers/CVehicleDrawHandler.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include
+
+#include "CEntityDrawHandler.hpp"
+
+namespace rage
+{
+ class CVehicleDrawHandler : public CEntityDrawHandler
+ {
+ public:
+ uint64_t qword30;
+ char gap38[848];
+ uint8_t m_primary_color; //0x0388
+ char gap389[3]; //0x0389
+ uint8_t m_pearlescent; //0x038C
+ char gap38D[3]; //0x038D
+ uint8_t m_secondary_color; //0x0390
+ char gap391[15]; //0x0391
+ uint8_t m_neon_blue; //0x03A0
+ uint8_t m_neon_green; //0x03A1
+ uint8_t m_neon_red; //0x03A2
+ char gap3A3[15]; //0x03A3
+ uint8_t m_spoiler; //0x03B2
+ uint8_t m_bumper_front; //0x03B3
+ uint8_t m_bumper_rear; //0x03B4
+ uint8_t m_sideskirts; //0x03B5
+ uint8_t m_exhaust; //0x03B6
+ uint8_t m_frame; //0x03B7
+ uint8_t m_grille; //0x03B8
+ uint8_t m_hood; //0x03B9
+ uint8_t m_fenders; //0x03BA
+ uint8_t m_bullbars; //0x03BB
+ uint8_t m_roof; //0x03BC
+ char gap3BD[3]; //0x03BD
+ uint8_t m_ornaments; //0x03C0
+ char gap3C1[1]; //0x03C1
+ uint8_t m_dail_design; //0x03C2
+ uint8_t m_sunstrips; //0x03C3
+ uint8_t m_seats; //0x03C4
+ uint8_t m_steering_wheel; //0x03C5
+ uint8_t m_column_shifter_levers; //0x03C6
+ char gap3C7[2]; //0x03C7
+ uint8_t m_truck_beds; //0x03C9
+ char gap3CA[4]; //0x03CA
+ uint8_t m_roll_cages; //0x03CE
+ uint8_t m_skid_plate; //0x03CF
+ uint8_t m_secondary_light_surrounds; //0x03D0
+ uint8_t m_hood_accessories; //0x03D1
+ uint8_t m_doors; //0x03D2
+ uint8_t m_snorkel; //0x03D3
+ uint8_t m_livery; //0x03D4
+ char gap3D5[1]; //0x03D5
+ uint8_t m_engine; //0x03D6
+ uint8_t m_brakes; //0x03D7
+ uint8_t m_transmission; //0x03D8
+ uint8_t m_horn; //0x03D9
+ uint8_t m_suspension; //0x03DA
+ uint8_t m_armor; //0x03DB
+ char gap3DC[1]; //0x03DC
+ uint8_t m_turbo; //0x03DD
+ char gap3DE[3]; //0x03DE
+ uint8_t m_xenon; //0x03E1
+ uint8_t m_tire_design; //0x03E2
+ char gap3E3[16]; //0x03E3
+ uint8_t m_truck_bed; //0x03F3
+ uint16_t m_modkit; //0x03F4
+ uint8_t byte3F6;
+ uint8_t byte3F7;
+ uint8_t byte3F8;
+ uint8_t m_wheel_color;
+ uint8_t byte3FA;
+ uint8_t byte3FB;
+ char gap3FC[3];
+ uint8_t m_window;
+ char gap400[2];
+ uint8_t m_neon_left;
+ uint8_t m_neon_right;
+ uint8_t m_neon_front;
+ uint8_t m_neon_rear;
+ char gap406[9];
+ uint32_t dword410;
+ uint32_t dword414;
+ };
+ static_assert(sizeof(CVehicleDrawHandler) == 0x418);
+}
diff --git a/classes/src/draw_handlers/fwDrawData.hpp b/classes/src/draw_handlers/fwDrawData.hpp
new file mode 100644
index 0000000000..7315f3f17a
--- /dev/null
+++ b/classes/src/draw_handlers/fwDrawData.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+
+namespace rage
+{
+#pragma pack(push, 4)
+ class fwDrawData
+ {
+ public:
+ std::uint64_t qword0;
+ std::uint64_t qword8;
+ char gap10[8];
+ std::uint32_t dword18;
+ std::uint32_t dword1C;
+ std::uint64_t qword20;
+ std::uint32_t dword28;
+ };
+ static_assert(sizeof(fwDrawData) == 0x2C);
+#pragma pack(pop)
+}
diff --git a/classes/src/entities/CAttackers.hpp b/classes/src/entities/CAttackers.hpp
new file mode 100644
index 0000000000..f0876388ec
--- /dev/null
+++ b/classes/src/entities/CAttackers.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+class CPed; //fwdec
+
+#pragma pack(push, 1)
+class CAttackers
+{
+public:
+ CPed* m_attacker0; //0x0000
+ char pad_0x0008[0x10]; //0x0008
+ CPed* m_attacker1; //0x0018
+ char pad_0x0020[0x10]; //0x0020
+ CPed* m_attacker2; //0x0030
+}; //Size=0x0038
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/entities/CDynamicEntity.hpp b/classes/src/entities/CDynamicEntity.hpp
new file mode 100644
index 0000000000..2d51bc7665
--- /dev/null
+++ b/classes/src/entities/CDynamicEntity.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "CEntity.hpp"
+#include "../network/netObject.hpp"
+
+#include
+
+namespace rage
+{
+ class CDynamicEntity : public CEntity
+ {
+ public:
+ class rage::netObject *m_net_object; //0x00D0
+ char gapD8[16];
+ uint64_t qwordE8;
+ };
+ static_assert(sizeof(CDynamicEntity) == 0xF0);
+}
diff --git a/classes/src/entities/CEntity.hpp b/classes/src/entities/CEntity.hpp
new file mode 100644
index 0000000000..14c7bb1c4a
--- /dev/null
+++ b/classes/src/entities/CEntity.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "fwEntity.hpp"
+
+#include
+
+class CEntityDrawHandler;
+
+namespace rage
+{
+ class CEntity : public rage::fwEntity
+ {
+ public:
+ virtual void* _0x120() = 0; // implemented only by CPed
+ virtual void UpdatePositionImpl() = 0; // 0x128
+ virtual void _0x130() = 0;
+ virtual void _0x138(void*) = 0;
+ virtual void _0x140() = 0;
+ virtual void _0x148(int) = 0;
+ virtual bool _0x150() = 0;
+ virtual CEntityDrawHandler* CreateDrawHandler() = 0; // 0x158
+ virtual int GetTypeFlags() = 0; // 0x160
+ virtual int GetTypeFlags2() = 0; // 0x168
+ virtual bool _0x170() = 0; // implemented only by CPickup
+ virtual bool _0x178() = 0;
+ virtual void _0x180(bool) = 0;
+ virtual bool _0x188() = 0;
+ virtual bool _0x190() = 0;
+ virtual void ClearDecals() = 0; // 0x198
+ virtual void GetModelBounds(rage::fvector3* bounds) = 0; // 0x1A0
+ virtual void GetModelBounds2(rage::fvector3* bounds) = 0; // 0x1A8
+ virtual float GetBoundingBoxSize() = 0; // 0x1B0
+ virtual float _0x1B8(void*) = 0;
+ virtual float _0x1C0(void*) = 0;
+ virtual rage::fvector3* _0x1C8() = 0;
+ virtual rage::fvector3* GetCameraOffset() = 0; // 0x1D0
+ virtual void GetCameraBasePosition(rage::fvector3* pos) = 0; // 0x1D8
+ virtual bool _0x1E0() = 0;
+ virtual bool Update() = 0; // 0x1E8 always returns true
+ virtual bool _0x1F0() = 0;
+ virtual void Warp(rage::fvector3* pos, float heading, bool) = 0; // 0x1F8
+
+
+ uint8_t gapB9; //0x00B9
+ char gapBA[6]; //0x00BA
+ uint32_t m_flags_3; //0x00C0
+ uint32_t m_flags_4; //0x00C4
+ uint32_t dwordC8;
+ uint32_t dwordCC;
+ };
+ static_assert(sizeof(CEntity) == 0xD0);
+}
diff --git a/classes/src/entities/CPhysical.hpp b/classes/src/entities/CPhysical.hpp
new file mode 100644
index 0000000000..1bf416b36d
--- /dev/null
+++ b/classes/src/entities/CPhysical.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "CDynamicEntity.hpp"
+#include "CAttackers.hpp"
+
+#include
+
+namespace rage
+{
+#pragma pack(push, 1)
+ class CPhysical : public CDynamicEntity
+ {
+ public:
+ char gapF0[144];
+ uint64_t qword180;
+ uint32_t m_damage_bits; //0x0188
+ uint8_t m_hostility; //0x018C
+ char gap18D[3];
+ uint8_t byte190;
+ char gap191[3];
+ uint32_t dword194;
+ char gap198[232];
+ float m_health; //0x0280
+ float m_maxhealth; //0x0284
+ class CAttackers* m_attackers;
+ char gap2B0[72];
+ uint64_t qword2F8;
+ uint64_t qword300;
+ uint32_t dword308;
+ };
+ static_assert(sizeof(CPhysical) == 0x2EC);
+#pragma pack(pop)
+}
diff --git a/classes/src/entities/fwEntity.hpp b/classes/src/entities/fwEntity.hpp
new file mode 100644
index 0000000000..fa03cfdddb
--- /dev/null
+++ b/classes/src/entities/fwEntity.hpp
@@ -0,0 +1,98 @@
+#pragma once
+
+#include "../base/CBaseModelInfo.hpp"
+#include "../base/CNavigation.hpp"
+#include "../base/fwExtensibleBase.hpp"
+#include "../base/atRTTI.hpp"
+
+#include "../draw_handlers/fwDrawData.hpp"
+
+#include
+
+class CMoveObjectPooledObject;
+
+namespace rage
+{
+ class fwDynamicEntityComponent;
+ class crmtRequestPose;
+ class crmtRequestIk;
+ class crFrameFilter;
+ class fwAudEntity;
+
+#pragma pack(push, 1)
+ class fwEntity : public fwExtensibleBase
+ {
+ public:
+ DEFINE_RAGE_RTTI(rage::fwEntity);
+
+ virtual void* _0x38(void*, void*) = 0;
+ virtual void AddExtension(void* extension) = 0; // 0x40
+ virtual void _0x48() = 0; // not implemented
+ virtual void _0x50() = 0; // only implemented by CEntityBatch
+ virtual void _0x58() = 0;
+ virtual void SetModelInfo(std::uint16_t* model_index) = 0; // 0x60
+ virtual void _0x68(int, fvector4*) = 0;
+ virtual void* _0x70(int) = 0;
+ virtual CNavigation* GetNavigation() = 0; // 0x78
+ virtual CMoveObjectPooledObject* CreateMoveObject() = 0; // 0x80
+ virtual std::uint32_t* GetType() = 0; // 0x88
+ virtual void _0x90() = 0;
+ virtual float _0x98() = 0;
+ virtual bool TryRequestInverseKinematics(rage::crmtRequestPose* pose, rage::crmtRequestIk* ik) = 0; // 0xA0 implemented only by CPed
+ virtual bool TryRequestFacialAnims(void*) = 0; // 0xA8 implemented only by CPed
+ virtual void* _0xB0() = 0;
+ virtual std::uint8_t _0xB8() = 0; // implemented only by CPed
+ virtual rage::crFrameFilter* GetFrameFilter() = 0; // 0xC0
+ virtual rage::fwAudEntity* GetEntityAudio() = 0; // 0xC8
+ virtual void _0xD0() = 0;
+ virtual void SetTransform(fmatrix44* matrix, bool update_pos) = 0; // 0xD8
+ virtual void SetTransform2(fmatrix44* matrix, bool update_pos) = 0; // 0xE0
+ virtual void SetPosition(fvector4* pos, bool update_pos) = 0; // 0xE8
+ virtual void SetHeading(float heading, bool update_pos) = 0; // 0xF0
+ virtual void SetEntityTypeFlags() = 0; // 0xF8
+ virtual void _0x100() = 0; // not implemented
+ virtual void UpdatePhysics(CNavigation* navigation) = 0; // 0x108
+ virtual void UpdatePhysics2(CNavigation* navigation) = 0; // 0x110
+ virtual void UpdatePosition() = 0; // 0x118
+
+ enum class EntityFlags
+ {
+ IS_VISIBLE = (1 << 0)
+ };
+
+ class CBaseModelInfo* m_model_info; //0x0020
+ uint8_t m_entity_type; //0x0028
+ char gap29; //0x0029
+ uint16_t gap2A; //0x002A
+ uint32_t m_flags; //0x002D
+ class CNavigation *m_navigation; //0x0030
+ uint16_t gap38; //0x0038
+ uint16_t gap3A; //0x003A
+ uint32_t gap3C; //0x003C
+ class rage::fwDynamicEntityComponent* m_dynamic_entity_component; //0x0040 (stores attachments and stuff)
+ class rage::fwDrawData* m_draw_data; //0x0048
+ class rage::fwDynamicEntityComponent* gap50; //0x0050
+ uint64_t gap58; //0x0058
+ fmatrix44 m_transformation_matrix; //0x0060
+ rage::fwEntity* m_render_focus_entity; //0x00A0
+ uint32_t m_render_focus_distance; //0x00A8
+ uint32_t m_flags_2; //0x00AC
+ uint32_t m_shadow_flags; //0x00B0
+ char gapB4[4]; //0x00B4
+ std::uint8_t byteB8; //0x00B8
+
+ rage::fvector3* get_position()
+ {
+ return reinterpret_cast(&m_transformation_matrix.rows[3]);
+ }
+
+ void model_to_world(const fvector3& model_coords, fvector3& world_coords)
+ {
+ world_coords.x = model_coords.x * m_transformation_matrix.data[0][0] + model_coords.y * m_transformation_matrix.data[1][0] + model_coords.z * m_transformation_matrix.data[2][0] + m_transformation_matrix.data[3][0];
+ world_coords.y = model_coords.x * m_transformation_matrix.data[0][1] + model_coords.y * m_transformation_matrix.data[1][1] + model_coords.z * m_transformation_matrix.data[2][1] + m_transformation_matrix.data[3][1];
+ world_coords.z = model_coords.x * m_transformation_matrix.data[0][2] + model_coords.y * m_transformation_matrix.data[1][2] + model_coords.z * m_transformation_matrix.data[2][2] + m_transformation_matrix.data[3][2];
+ }
+ };
+ static_assert(sizeof(fwEntity) == 0xB9);
+#pragma pack(pop)
+}
diff --git a/classes/src/enums/eExplosionTag.hpp b/classes/src/enums/eExplosionTag.hpp
new file mode 100644
index 0000000000..4cfca5de4e
--- /dev/null
+++ b/classes/src/enums/eExplosionTag.hpp
@@ -0,0 +1,92 @@
+#pragma once
+
+#include
+
+enum eExplosionTag : int32_t
+{
+ DONTCARE = -1,
+ GRENADE,
+ GRENADELAUNCHER,
+ STICKYBOMB,
+ MOLOTOV,
+ ROCKET,
+ TANKSHELL,
+ HI_OCTANE,
+ CAR,
+ PLANE,
+ PETROL_PUMP,
+ BIKE,
+ DIR_STEAM,
+ DIR_FLAME,
+ DIR_WATER_HYDRANT,
+ DIR_GAS_CANISTER,
+ BOAT,
+ SHIP_DESTROY,
+ TRUCK,
+ BULLET,
+ SMOKEGRENADELAUNCHER,
+ SMOKEGRENADE,
+ BZGAS,
+ FLARE,
+ GAS_CANISTER,
+ EXTINGUISHER,
+ _0x988620B8,
+ EXP_TAG_TRAIN,
+ EXP_TAG_BARREL,
+ EXP_TAG_PROPANE,
+ EXP_TAG_BLIMP,
+ EXP_TAG_DIR_FLAME_EXPLODE,
+ EXP_TAG_TANKER,
+ PLANE_ROCKET,
+ EXP_TAG_VEHICLE_BULLET,
+ EXP_TAG_GAS_TANK,
+ EXP_TAG_BIRD_CRAP,
+ EXP_TAG_RAILGUN,
+ EXP_TAG_BLIMP2,
+ EXP_TAG_FIREWORK,
+ EXP_TAG_SNOWBALL,
+ EXP_TAG_PROXMINE,
+ EXP_TAG_VALKYRIE_CANNON,
+ EXP_TAG_AIR_DEFENCE,
+ EXP_TAG_PIPEBOMB,
+ EXP_TAG_VEHICLEMINE,
+ EXP_TAG_EXPLOSIVEAMMO,
+ EXP_TAG_APCSHELL,
+ EXP_TAG_BOMB_CLUSTER,
+ EXP_TAG_BOMB_GAS,
+ EXP_TAG_BOMB_INCENDIARY,
+ EXP_TAG_BOMB_STANDARD,
+ EXP_TAG_TORPEDO,
+ EXP_TAG_TORPEDO_UNDERWATER,
+ EXP_TAG_BOMBUSHKA_CANNON,
+ EXP_TAG_BOMB_CLUSTER_SECONDARY,
+ EXP_TAG_HUNTER_BARRAGE,
+ EXP_TAG_HUNTER_CANNON,
+ EXP_TAG_ROGUE_CANNON,
+ EXP_TAG_MINE_UNDERWATER,
+ EXP_TAG_ORBITAL_CANNON,
+ EXP_TAG_BOMB_STANDARD_WIDE,
+ EXP_TAG_EXPLOSIVEAMMO_SHOTGUN,
+ EXP_TAG_OPPRESSOR2_CANNON,
+ EXP_TAG_MORTAR_KINETIC,
+ EXP_TAG_VEHICLEMINE_KINETIC,
+ EXP_TAG_VEHICLEMINE_EMP,
+ EXP_TAG_VEHICLEMINE_SPIKE,
+ EXP_TAG_VEHICLEMINE_SLICK,
+ EXP_TAG_VEHICLEMINE_TAR,
+ EXP_TAG_SCRIPT_DRONE,
+ EXP_TAG_RAYGUN,
+ EXP_TAG_BURIEDMINE,
+ EXP_TAG_SCRIPT_MISSILE,
+ EXP_TAG_RCTANK_ROCKET,
+ EXP_TAG_BOMB_WATER,
+ EXP_TAG_BOMB_WATER_SECONDARY,
+ _0xF728C4A9,
+ _0xBAEC056F,
+ EXP_TAG_FLASHGRENADE,
+ EXP_TAG_STUNGRENADE,
+ _0x763D3B3B,
+ EXP_TAG_SCRIPT_MISSILE_LARGE,
+ EXP_TAG_SUBMARINE_BIG,
+ EXP_TAG_EMPLAUNCHER_EMP,
+};
\ No newline at end of file
diff --git a/classes/src/enums/eHandlingType.hpp b/classes/src/enums/eHandlingType.hpp
new file mode 100644
index 0000000000..7257da50ef
--- /dev/null
+++ b/classes/src/enums/eHandlingType.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+enum class eHandlingType
+{
+ HANDLING_TYPE_BIKE,
+ HANDLING_TYPE_FLYING,
+ HANDLING_TYPE_VERTICAL_FLYING,
+ HANDLING_TYPE_BOAT,
+ HANDLING_TYPE_SEAPLANE,
+ HANDLING_TYPE_SUBMARINE,
+ HANDLING_TYPE_TRAIN,
+ HANDLING_TYPE_TRAILER,
+ HANDLING_TYPE_CAR,
+ HANDLING_TYPE_WEAPON,
+ HANDLING_TYPE_MAX_TYPES
+};
\ No newline at end of file
diff --git a/classes/src/game_files/CGameConfig.hpp b/classes/src/game_files/CGameConfig.hpp
new file mode 100644
index 0000000000..1df087bf13
--- /dev/null
+++ b/classes/src/game_files/CGameConfig.hpp
@@ -0,0 +1,262 @@
+#pragma once
+#include "rage/atArray.hpp"
+
+class CPoolSizes;
+class CPoolSize;
+class CGameConfig;
+
+#pragma pack(push, 1)
+
+class CPoolSize {
+public:
+ char* m_pool;
+ uint32_t m_size;
+};
+static_assert(sizeof(CPoolSize) == 0xC);
+
+class CStackSizeData {
+public:
+ rage::joaat_t m_stack_name;
+ int32_t m_size_of_stack;
+ int32_t m_number_of_stacks_of_this_size;
+
+ inline CStackSizeData(rage::joaat_t name, int size, int num) :
+ m_stack_name(name),
+ m_size_of_stack(size),
+ m_number_of_stacks_of_this_size(num)
+ {
+ }
+
+ inline CStackSizeData(const std::string& name, int size, int num) :
+ m_stack_name(rage::joaat(name)),
+ m_size_of_stack(size),
+ m_number_of_stacks_of_this_size(num)
+ {
+ }
+};
+static_assert(sizeof(CStackSizeData) == 0xC);
+
+namespace rage
+{
+ class parStructure;
+
+ class fwConfig
+ {
+ public:
+ virtual ~fwConfig() = 0;
+
+ virtual void copy_data_from_config(fwConfig* config) = 0;
+
+ virtual fwConfig* clone_config() = 0;
+
+ virtual parStructure* get_structure() = 0;
+
+ rage::atArray m_pool_sizes;
+ char padding[0x8];
+ };
+ static_assert(sizeof(fwConfig) == 0x20);
+
+ template
+ class fwConfigManagerImpl
+ {
+ public:
+ virtual ~fwConfigManagerImpl() = 0;
+
+ virtual T* create_config() = 0;
+
+ char padding[0x10];
+
+ T* m_config;
+ };
+ static_assert(sizeof(fwConfigManagerImpl) == 0x20);
+};
+
+class CConfigPopulation
+{
+public:
+ int32_t m_scenario_peds_multiplier_base; //0x0000
+ int32_t m_scenario_peds_multiplier; //0x0004
+ int32_t m_ambient_peds_multiplier_base; //0x0008
+ int32_t m_ambient_peds_multiplier; //0x000C
+ int32_t m_max_total_peds_base; //0x0010
+ int32_t m_max_total_peds; //0x0014
+ int32_t m_ped_memory_multiplier; //0x0018
+ int32_t m_peds_for_vehicles_base; //0x001C
+ int32_t m_peds_for_vehicles; //0x0020
+ int32_t m_vehicle_timeslice_max_updates_per_frame_base; //0x0024
+ int32_t m_vehicle_timeslice_max_updates_per_frame; //0x0028
+ int32_t m_vehicle_ambient_density_multiplier_base; //0x002C
+ int32_t m_vehicle_ambient_density_multiplier; //0x0030
+ int32_t m_vehicle_memory_multiplier; //0x0034
+ int32_t m_vehicle_parked_density_multiplier_base; //0x0038
+ int32_t m_vehicle_parked_density_multiplier; //0x003C
+ int32_t m_vehicle_low_prio_parked_density_multiplier_base; //0x0040
+ int32_t m_vehicle_low_prio_parked_density_multiplier; //0x0044
+ int32_t m_vehicle_upper_limit_base; //0x0048
+ int32_t m_vehicle_upper_limit; //0x004C
+ int32_t m_vehicle_upper_limit_mp; //0x0050
+ int32_t m_vehicle_parked_upper_limit_base; //0x0054
+ int32_t m_vehicle_parked_upper_limit; //0x0058
+ int32_t m_vehicle_keyhole_shape_inner_thickness_base; //0x005C
+ int32_t m_vehicle_keyhole_shape_inner_thickness; //0x0060
+ int32_t m_vehicle_keyhole_shape_outer_thickness_base; //0x0064
+ int32_t m_vehicle_keyhole_shape_outer_thickness; //0x0068
+ int32_t m_vehicle_keyhole_shape_inner_radius_base; //0x006C
+ int32_t m_vehicle_keyhole_shape_inner_radius; //0x0070
+ int32_t m_vehicle_keyhole_shape_outer_radius_base; //0x0074
+ int32_t m_vehicle_keyhole_shape_outer_radius; //0x0078
+ int32_t m_vehicle_keyhole_side_wall_thickness_base; //0x007C
+ int32_t m_vehicle_keyhole_side_wall_thickness; //0x0080
+ int32_t m_vehicle_max_creation_distance_base; //0x0084
+ int32_t m_vehicle_max_creation_distance; //0x0088
+ int32_t m_vehicle_max_creation_distance_offscreen_base; //0x008C
+ int32_t m_vehicle_max_creation_distance_offscreen; //0x0090
+ int32_t m_vehicle_cull_range_base; //0x0094
+ int32_t m_vehicle_cull_range; //0x0098
+ int32_t m_vehicle_cull_range_on_screen_scale_base; //0x009C
+ int32_t m_vehicle_cull_range_on_screen_scale; //0x00A0
+ int32_t m_vehicle_cull_range_off_screen_base; //0x00A4
+ int32_t m_vehicle_cull_range_off_screen; //0x00A8
+ int32_t m_density_based_removal_rate_scale_base; //0x00AC
+ int32_t m_density_based_removal_rate_scale; //0x00B0
+ int32_t m_density_based_removal_target_headroom_base; //0x00B4
+ int32_t m_density_based_removal_target_headroom; //0x00B8
+ rage::atArray m_vehicle_spacing_base; // TODO: these are atFixedArrays
+ char pad_00CC[48]; //0x00CC
+ rage::atArray m_vehicle_spacing;
+ char pad_010C[48]; //0x010C
+ int32_t m_players_road_scan_distance_base; //0x013C
+ int32_t m_players_road_scan_distance; //0x0140
+ rage::atArray m_player_road_density_inc_base;
+ char pad_0154[48]; //0x0154
+ rage::atArray m_player_road_density_inc;
+ char pad_0194[48]; //0x0194
+ rage::atArray m_non_player_road_density_dec_base;
+ char pad_01D4[56]; //0x01D4
+ rage::atArray m_non_player_road_density_dec;
+ char pad_021C[40]; //0x021C
+ int32_t m_vehicle_population_frame_rate_base; //0x0244
+ int32_t m_vehicle_population_frame_rate; //0x0248
+ int32_t m_vehicle_population_cycles_per_frame_base; //0x024C
+ int32_t m_vehicle_population_cycles_per_frame; //0x0250
+ int32_t m_vehicle_population_frame_rate_mp_base; //0x0254
+ int32_t m_vehicle_population_frame_rate_mp; //0x0258
+ int32_t m_vehicle_population_cycles_per_frame_mp_base; //0x025C
+ int32_t m_vehicle_population_cycles_per_frame_mp; //0x0260
+ int32_t m_ped_population_frame_rate_base; //0x0264
+ int32_t m_ped_population_frame_rate; //0x0268
+ int32_t m_ped_population_cycles_per_frame_base; //0x026C
+ int32_t m_ped_population_cycles_per_frame; //0x0270
+ int32_t m_ped_population_frame_rate_mp_base; //0x0274
+ int32_t m_ped_population_frame_rate_mp; //0x0278
+ int32_t m_ped_population_cycles_per_frame_mp_base; //0x027C
+ int32_t m_ped_population_cycles_per_frame_mp; //0x0280
+};
+static_assert(sizeof(CConfigPopulation) == 0x284);
+
+class CConfig2DEffects // looks unused
+{
+public:
+ int32_t m_max_attrs_audio; //0x0000
+ int32_t m_max_attrs_buoyancy; //0x0004
+ int32_t m_max_attrs_decal; //0x0008
+ int32_t m_max_attrs_explosion; //0x000C
+ int32_t m_max_attrs_ladder; //0x0010
+ char pad_0014[8]; //0x0014
+ int32_t m_max_attrs_light_shaft; //0x001C
+ int32_t m_max_attrs_particle; //0x0020
+ int32_t m_max_attrs_proc_obj; //0x0024
+ int32_t m_max_attrs_scroll_bar; //0x0028
+ int32_t m_max_attrs_spawn_point; //0x002C
+ char pad_0030[8]; //0x0030
+ int32_t m_max_attrs_wind_disturbance; //0x0038
+ int32_t m_max_attrs_world_point; //0x003C
+ int32_t m_0xFC5DD116; //0x0040
+ int32_t m_max_effects_world_2d; //0x0044
+ char pad[4];
+};
+static_assert(sizeof(CConfig2DEffects) == 0x4C);
+
+class CConfigModelInfo
+{
+public:
+ char* m_default_player_name; //0x0000
+ char* m_default_prologue_player_name; //0x0008
+ int32_t m_max_base_model_infos; //0x0010
+ int32_t m_max_comp_entity_model_infos; //0x0014
+ int32_t m_max_mlo_instances; //0x0018
+ int32_t m_max_mlo_model_infos; //0x001C
+ int32_t m_max_ped_model_infos; //0x0020
+ int32_t m_max_time_model_infos; //0x0024
+ int32_t m_max_vehicle_model_infos; //0x0028
+ int32_t m_max_weapon_model_infos; //0x002C
+ int32_t m_max_extra_ped_model_infos; //0x0030
+ int32_t m_max_extra_vehicle_model_infos; //0x0034
+ int32_t m_max_extra_weapon_model_infos; //0x0038
+ int32_t m_unk;
+};
+static_assert(sizeof(CConfigModelInfo) == 0x40);
+
+class CConfigExtensions
+{
+public:
+ int32_t m_max_door_extensions;
+ int32_t m_max_light_extensions;
+ int32_t m_max_spawn_point_override_extensions;
+ int32_t m_max_expression_extensions;
+ int32_t m_0xBDE77A4F;
+};
+static_assert(sizeof(CConfigExtensions) == 0x14);
+
+class CConfigStreamingEngine
+{
+public:
+ int32_t m_archive_count;
+ int32_t m_physical_streaming_buffer;
+ int32_t m_virtual_streaming_buffer;
+};
+static_assert(sizeof(CConfigStreamingEngine) == 0xC);
+
+class CConfigOnlineServices
+{
+public:
+ char* m_ros_title_name;
+ int32_t m_ros_title_version;
+ int32_t m_sc_version;
+ int64_t m_steam_app_id;
+ char* m_title_directory_name;
+ char* m_multiplayer_session_template_name;
+ char* m_sc_auth_title_id;
+};
+static_assert(sizeof(CConfigOnlineServices) == 0x30);
+
+class CConfigUGCDescriptions
+{
+public:
+ int32_t m_max_description_length;
+ int32_t m_max_num_descriptions;
+ int32_t m_size_of_description_buffer;
+};
+static_assert(sizeof(CConfigUGCDescriptions) == 0xC);
+
+class CConfigScriptStackSizes
+{
+public:
+ rage::atArray m_stack_size_data;
+};
+static_assert(sizeof(CConfigScriptStackSizes) == 0x10);
+
+class CGameConfig : public rage::fwConfig {
+public:
+ CConfigPopulation m_config_population;
+ CConfig2DEffects m_config_2d_effects;
+ CConfigModelInfo m_config_model_info;
+ CConfigExtensions m_config_extensions;
+ CConfigStreamingEngine m_config_streaming_engine;
+ CConfigOnlineServices m_config_online_services;
+ CConfigUGCDescriptions m_config_ugc_descriptions;
+ char padding[0x488 - 0x38C]; // CConfigNetScriptBroadcastData
+ CConfigScriptStackSizes m_config_script_stack_sizes;
+ // TODO: more stuff down here
+};
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/misc/CTunables.hpp b/classes/src/misc/CTunables.hpp
new file mode 100644
index 0000000000..d029c1eeb7
--- /dev/null
+++ b/classes/src/misc/CTunables.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include
+#include "../base/datBase.hpp"
+
+enum eTunableType
+{
+ TunableType_DONTCARE = -1,
+ TunableType_UNK0,
+ TunableType_4BYTE,
+ TunableType_1BYTE,
+};
+
+class CTunables : public rage::datBase
+{
+public:
+ char pad_0000[104]; //0x0008
+ uint64_t m_bPtr; //0x0070
+ uint16_t m_bCount; //0x0078
+ char pad_007A[0x4E]; //0x007A
+}; //Size: 0x00C8
+static_assert(sizeof(CTunables) == 0xC8);
diff --git a/classes/src/misc/vfx/TimecycleKeyframeData.hpp b/classes/src/misc/vfx/TimecycleKeyframeData.hpp
new file mode 100644
index 0000000000..1a4e3fdd9a
--- /dev/null
+++ b/classes/src/misc/vfx/TimecycleKeyframeData.hpp
@@ -0,0 +1,96 @@
+#pragma once
+
+class TimecycleKeyframeData
+{
+public:
+ char pad_0000[32]; //0x0000
+ rage::fvector4 m_azimuth_east; //0x0020
+ float m_azimuth_east_intensity; //0x0030
+ char pad_0034[28]; //0x0034
+ rage::fvector4 m_azimuth_west; //0x0050
+ float m_azimuth_west_intensity; //0x0060
+ char pad_0064[28]; //0x0064
+ rage::fvector4 m_azimuth_transition; //0x0080
+ float m_azimuth_transition_intensity; //0x0090
+ char pad_0094[4]; //0x0094
+ float m_azimuth_transition_position; //0x0098
+ char pad_009C[20]; //0x009C
+ rage::fvector4 m_zenith; //0x00B0
+ float m_zenith_intensity; //0x00C0
+ char pad_00C4[28]; //0x00C4
+ rage::fvector4 m_zenith_transition; //0x00E0
+ float m_zenith_transition_intensity; //0x00F0
+ float m_zenith_transition_position; //0x00F4
+ float m_zenith_transition_east_blend; //0x00F8
+ float m_zenith_transition_west_blend; //0x00FC
+ float m_zenith_blend_start; //0x0100
+ char pad_0104[60]; //0x0104
+ rage::fvector3 m_plane; //0x0140
+ float m_plane_intensity; //0x014C
+ char pad_0150[52]; //0x0150
+ float m_hdr; //0x0184
+ float m_unk_188; //0x0188
+ bool m_update_sky_attributes; //0x018C
+ char pad_018D[3]; //0x018D
+ uint32_t m_unk_190; //0x0190
+ uint32_t m_unk_194; //0x0194
+ char pad_0198[8]; //0x0198
+ rage::fvector4 m_unk_1A0; //0x01A0
+ char pad_01AC[16]; //0x01AC
+ rage::fvector4 m_sun; //0x01C0
+ char pad_01CC[32]; //0x01CC
+ rage::fvector4 m_sun_disc; //0x01F0
+ char pad_01FC[32]; //0x01FC
+ float m_sun_disc_size; //0x0220
+ float m_sun_hdr; //0x0224
+ float m_sun_miephase; //0x0228
+ float m_sun_miescatter; //0x022C
+ float m_sun_mie_intensity_mult; //0x0230
+ char pad_0234[28]; //0x0234
+ rage::fvector4 m_unk_250; //0x0250
+ char pad_025C[16]; //0x025C
+ float m_cloud_shadow_strength; //0x0270
+ float m_cloud_density_mult; //0x0274
+ float m_cloud_density_bias; //0x0278
+ float m_cloud_fadeout; //0x027C
+ char pad_0280[32]; //0x0280
+ float m_unk_2A0; //0x02A0
+ float m_cloud_offset; //0x02A4
+ float m_cloud_overall_color; //0x02A8
+ float m_cloud_hdr; //0x02AC
+ char pad_02B0[32]; //0x02B0
+ float m_cloud_dither_strength; //0x02D0
+ char pad_02D4[44]; //0x02D4
+ float m_cloud_edge_strength; //0x0300
+ char pad_0304[4]; //0x0304
+ float m_cloud_overall_strength; //0x0308
+ char pad_030C[16]; //0x030C
+ rage::fvector4 m_unk_320; //0x031C
+ rage::fvector4 m_cloud_base; //0x032C
+ rage::fvector4 m_unk_340; //0x033C
+ char pad_0348[16]; //0x0348
+ rage::fvector4 m_cloud_1; //0x035C
+ char pad_0368[20]; //0x0368
+ rage::fvector4 m_cloud_mid; //0x0380
+ char pad_038C[32]; //0x038C
+ float m_unk_380; //0x03B0
+ float m_small_cloud_detail_strength; //0x03B4
+ float m_small_cloud_density_mult; //0x03B8
+ float m_unk_3BC; //0x03BC
+ char pad_03C0[32]; //0x03C0
+ rage::fvector4 m_small_cloud; //0x03E0
+ char pad_03EC[32]; //0x03EC
+ float m_sun_influence_radius; //0x0410
+ float m_sun_scatter_inten; //0x0414
+ float m_moon_influence_radius; //0x0418
+ float m_moon_scatter_inten; //0x041C
+ char pad_0420[212]; //0x0420
+ float m_stars_iten; //0x04F4
+ char pad_04F8[60]; //0x04F8
+ float m_moon_disc_size; //0x0534
+ char pad_0538[24]; //0x0538
+ rage::fvector4 m_moon; //0x0550
+ float m_moon_intensity; //0x0560
+ char pad_0564[140]; //0x0564
+}; //Size: 0x05F0
+static_assert(sizeof(TimecycleKeyframeData) == 0x5F0);
\ No newline at end of file
diff --git a/classes/src/netsync/CProjectBaseSyncDataNode.hpp b/classes/src/netsync/CProjectBaseSyncDataNode.hpp
new file mode 100644
index 0000000000..920c11a3dd
--- /dev/null
+++ b/classes/src/netsync/CProjectBaseSyncDataNode.hpp
@@ -0,0 +1,46 @@
+#pragma once
+#include "netSyncDataNode.hpp"
+#include "NodeCommonDataOperations.hpp"
+
+namespace rage
+{
+ class netSyncData;
+ class netObject;
+}
+
+class CProjectBaseSyncDataNode : public rage::netSyncDataNode
+{
+public:
+ virtual bool IsSyncNode() { return false; } // 0x50
+ virtual bool _0x58() { return false; } // 0x58
+ virtual bool IsGlobalFlags() { return false; } // 0x60
+ virtual void DoPreCache(rage::netSyncData* data) {} // 0x68
+ virtual std::uint8_t GetSyncFrequency(int index) { return 0; } // 0x70
+ virtual int GetSyncInterval(int index) { return 0; } // 0x78
+ virtual int GetBandwidthForPlayer(int player) { return 200; } // 0x80 (should always return 200)
+ virtual void _0x88(void*) {} // 0x88
+ virtual bool _0x90(void*, void*, int, int, int) { return false; } // 0x90
+ virtual int CalculateSize() { return 0; } // 0x98 need to verify later
+ virtual bool IsPreCacheDisabled() { return false; } // 0xA0
+ virtual bool CanApply(rage::netObject* object) { return false; } // 0xA8
+ virtual int GetPlayersInScope() { return -1; } // 0xB0
+ virtual void DeserializeImpl() {} // 0xB8 need to verify later
+ virtual void SerializeImpl() {} // 0xC0 need to verify later
+ virtual int CalculateSize2() { return 0; } // 0xC8
+ virtual int _0xD0() { return 0; } // 0xD0 calls NodeCommonDataOperations::Unk()
+ virtual void Log() {} // 0xD8
+ virtual bool CanPreCache(int) { return false; } // 0xE0 arg is always zero afaik
+ virtual bool CanBeEmpty() { return false; } // 0xE8
+ virtual bool IsEmpty() { return false; } // 0xF0 returns true if all data is default
+ virtual void SetEmpty() {} // 0xF8 sets all data to their default values
+ virtual void Log2() {} // 0x100
+ virtual void ResetScriptData() {} // 0x108
+ virtual bool _0x110() { return false; } // 0x110
+
+private:
+ NodeCommonDataOperations m_common_data_operations; // 0xB0 this is generally invalidated by MoveCommonDataOpsVFT()
+};
+static_assert(sizeof(CProjectBaseSyncDataNode) == 0xC0);
+
+class CSyncDataNodeFrequent : public CProjectBaseSyncDataNode {};
+class CSyncDataNodeInfrequent : public CProjectBaseSyncDataNode {};
\ No newline at end of file
diff --git a/classes/src/netsync/CProjectSyncTree.hpp b/classes/src/netsync/CProjectSyncTree.hpp
new file mode 100644
index 0000000000..4751bbd5b0
--- /dev/null
+++ b/classes/src/netsync/CProjectSyncTree.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include "netSyncTree.hpp"
+
+class CProjectSyncTree : public rage::netSyncTree
+{
+ void* m_unk_data;
+ int m_unk_data_size;
+ char pad_04C4[4];
+};
+static_assert(sizeof(CProjectSyncTree) == 0x4C8);
\ No newline at end of file
diff --git a/classes/src/netsync/NodeCommonDataOperations.hpp b/classes/src/netsync/NodeCommonDataOperations.hpp
new file mode 100644
index 0000000000..ee5b642210
--- /dev/null
+++ b/classes/src/netsync/NodeCommonDataOperations.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+namespace rage
+{
+ class datBitBuffer;
+ class netSyncDataNode;
+}
+
+class NodeCommonDataOperations
+{
+public:
+ virtual ~NodeCommonDataOperations() = default;
+ virtual void ReadFromBuffer(rage::netSyncDataNode* node) {}; // 0x08
+ virtual void WriteToBuffer(rage::netSyncDataNode* node) {}; // 0x10
+ virtual void Unk() {}; // 0x18
+ virtual int CalculateSize(rage::netSyncDataNode* node) { return 0; }; // 0x20
+ virtual int CalculateSize2(rage::netSyncDataNode* node) { return 0; }; // 0x28
+ virtual void LogSyncData(rage::netSyncDataNode* node) {}; // 0x30
+ virtual void LogSyncData2(rage::netSyncDataNode* node) {}; // 0x38
+
+ rage::datBitBuffer* m_buffer; // 0x8
+};
+static_assert(sizeof(NodeCommonDataOperations) == 0x10);
\ No newline at end of file
diff --git a/classes/src/netsync/netSyncDataNode.hpp b/classes/src/netsync/netSyncDataNode.hpp
new file mode 100644
index 0000000000..485dc91c7c
--- /dev/null
+++ b/classes/src/netsync/netSyncDataNode.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "netSyncNodeBase.hpp"
+
+namespace rage
+{
+#pragma pack(push, 8)
+ class netSyncDataNode : public netSyncNodeBase
+ {
+ public:
+ uint32_t flags; //0x40
+ uint32_t pad3; //0x44
+ uint64_t pad4; //0x48
+
+ netSyncDataNode* parentData; //0x50
+ uint32_t childCount; //0x58
+ netSyncDataNode* children[8]; //0x5C
+ uint8_t syncFrequencies[8]; //0x9C
+ void* commonDataOpsVFT; //0xA8 wtf
+ };
+ static_assert(sizeof(netSyncDataNode) == 0xB0);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/netsync/netSyncNodeBase.hpp b/classes/src/netsync/netSyncNodeBase.hpp
new file mode 100644
index 0000000000..6931aed944
--- /dev/null
+++ b/classes/src/netsync/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() { return false; }; // 0x08
+ virtual bool IsParentNode() { return false; }; // 0x10
+ virtual void MoveCommonDataOpsVFT() {}; // 0x18
+ virtual void ClearChildren() {}; // 0x20
+ virtual void _0x28(void*, void*, void*, int* out_count) {}; // 0x28
+ virtual bool Serialize(int flags, int flags2, void*, rage::datBitBuffer* buffer, int, void*, bool, int*, int* num_serialized) { return false; } // 0x30
+ virtual bool Deserialize(int flags, int flags2, rage::datBitBuffer* buffer, void*) { return false; } // 0x38
+ virtual int CalculateSize(int flags, int flags2, void*) { return 0; } // 0x40
+ virtual int CalculateSize2(int flags, int flags2, bool) { return 0; } // 0x48
+
+ netSyncNodeBase* m_next_sibling; //0x0008
+ netSyncNodeBase* m_prev_sibling; //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_first_child; //0x0038
+ }; //Size: 0x0040
+ static_assert(sizeof(netSyncNodeBase) == 0x40);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/netsync/netSyncParentNode.hpp b/classes/src/netsync/netSyncParentNode.hpp
new file mode 100644
index 0000000000..ec0935ae01
--- /dev/null
+++ b/classes/src/netsync/netSyncParentNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include "netSyncNodeBase.hpp"
+
+namespace rage
+{
+ class netSyncParentNode : public netSyncNodeBase
+ {
+ public:
+ char pad_0040[32];
+ };
+ static_assert(sizeof(netSyncParentNode) == 0x60);
+}
+
+class CProjectBaseSyncParentNode : public rage::netSyncParentNode {};
\ No newline at end of file
diff --git a/classes/src/netsync/netSyncTree.hpp b/classes/src/netsync/netSyncTree.hpp
new file mode 100644
index 0000000000..e7dc492eb6
--- /dev/null
+++ b/classes/src/netsync/netSyncTree.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "netSyncNodeBase.hpp"
+
+namespace rage
+{
+#pragma pack(push, 1)
+ class netSyncTree
+ {
+ public:
+ virtual ~netSyncTree() = default;
+
+ char pad_0008[8]; //0x0008
+ netSyncNodeBase* m_next_sync_node; //0x0010
+ netSyncNodeBase* m_last_sync_node; //0x0018
+ uint32_t m_child_node_count; //0x0020
+ uint32_t m_unk_array_count; //0x0024
+ char pad_0028[8]; //0x0028
+ netSyncNodeBase* m_child_nodes[42]; //0x0030
+ uint32_t m_child_node_max_count; //0x0180
+ netSyncNodeBase* m_unk_array[32]; //0x0188
+ uint32_t m_unk_array_max_count; //0x0288
+ char pad_0290[560]; //0x0290
+ }; //Size: 0x0030
+ static_assert(sizeof(netSyncTree) == 0x4B8);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/CPedComponents.hpp b/classes/src/netsync/nodes/CPedComponents.hpp
new file mode 100644
index 0000000000..d6d75ec82e
--- /dev/null
+++ b/classes/src/netsync/nodes/CPedComponents.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include
+
+#pragma pack(push, 4)
+class CPedComponents
+{
+public:
+ uint32_t m_component_bitset; //0x0
+ char pad_0x4[4]; //0x4
+ uint32_t unk_0x8[12]; //0x8
+ uint32_t m_drawables[12]; //0x38
+ uint32_t m_textures[12]; //0x68
+ uint32_t m_palettes[12]; //0x98
+
+ inline uint32_t get_drawable(int index)
+ {
+ if (m_component_bitset & (1 << index))
+ {
+ return m_drawables[index];
+ }
+
+ return 0;
+ }
+
+ inline uint32_t get_texture(int index)
+ {
+ if (m_component_bitset & (1 << index))
+ {
+ return m_textures[index];
+ }
+
+ return 0;
+ }
+
+ inline uint32_t get_palette(int index)
+ {
+ if (m_component_bitset & (1 << index))
+ {
+ return m_palettes[index];
+ }
+
+ return 0;
+ }
+};
+static_assert(sizeof(CPedComponents) == 0xC8);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/automobile/CAutomobileCreationNode.hpp b/classes/src/netsync/nodes/automobile/CAutomobileCreationNode.hpp
new file mode 100644
index 0000000000..e48688258b
--- /dev/null
+++ b/classes/src/netsync/nodes/automobile/CAutomobileCreationNode.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+class CAutomobileCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_all_doors_closed; //0x00C0
+ bool m_door_closed[10]; //0x00C1
+};
+static_assert(sizeof(CAutomobileCreationDataNode) == 0xD0);
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/door/CDoorCreationDataNode.hpp b/classes/src/netsync/nodes/door/CDoorCreationDataNode.hpp
new file mode 100644
index 0000000000..8600a9a725
--- /dev/null
+++ b/classes/src/netsync/nodes/door/CDoorCreationDataNode.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CDoorCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_model; //0x00C0
+ char pad_00C4[12]; //0x00C4
+ rage::fvector3 m_pos; //0x00D0
+ char pad_00DC[12]; //0x00DC
+ bool m_is_script_door; //0x00E8
+ bool m_player_wants_control; //0x00E9
+}; //Size: 0x00EC
+static_assert(sizeof(CDoorCreationDataNode) == 0xEC);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/door/CDoorMovementDataNode.hpp b/classes/src/netsync/nodes/door/CDoorMovementDataNode.hpp
new file mode 100644
index 0000000000..739a0eca86
--- /dev/null
+++ b/classes/src/netsync/nodes/door/CDoorMovementDataNode.hpp
@@ -0,0 +1,17 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CDoorMovementDataNode : CSyncDataNodeFrequent
+{
+public:
+ bool m_is_manual_door; // 0xC0
+ float m_open_ratio; // 0xC4
+ bool m_opening; // 0xC8
+ bool m_fully_open; // 0xC9
+ bool m_closed; // 0xCA
+};
+static_assert(sizeof(CDoorMovementDataNode) == 0xCC);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/door/CDoorScriptGameStateDataNode.hpp b/classes/src/netsync/nodes/door/CDoorScriptGameStateDataNode.hpp
new file mode 100644
index 0000000000..d1b4a6041e
--- /dev/null
+++ b/classes/src/netsync/nodes/door/CDoorScriptGameStateDataNode.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+struct CDoorScriptGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_door_system_state; // 0xC0
+ float m_automatic_distance; // 0xC4
+ float m_slide_rate; // 0xC8
+ bool m_has_broken_flags; // 0xCC
+ uint32_t m_broken_flags; // 0xD0
+ bool m_has_damaged_flags; // 0xD4
+ uint32_t m_damaged_flags; // 0xD8
+ bool m_hold_open; // 0xDC
+};
+static_assert(sizeof(CDoorScriptGameStateDataNode) == 0xE0);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/door/CDoorScriptInfoDataNode.hpp b/classes/src/netsync/nodes/door/CDoorScriptInfoDataNode.hpp
new file mode 100644
index 0000000000..44cf2f8dca
--- /dev/null
+++ b/classes/src/netsync/nodes/door/CDoorScriptInfoDataNode.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "script/CGameScriptObjInfo.hpp"
+
+#pragma pack(push, 4)
+struct CDoorScriptInfoDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_has_script_info;
+ int m_pad;
+ CGameScriptObjInfo m_script_info;
+ uint32_t m_door_system_hash;
+ bool m_existing_door_system_entry;
+};
+static_assert(sizeof(CDoorScriptInfoDataNode) == 0x120);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp b/classes/src/netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp
new file mode 100644
index 0000000000..3eefe6ca26
--- /dev/null
+++ b/classes/src/netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 1)
+struct CDecorator
+{
+ uint32_t m_type;
+ uint32_t m_name_hash;
+ uint32_t m_value;
+};
+#pragma pack(pop)
+
+#pragma pack(push, 4)
+class CDynamicEntityGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_interior_index; // 0x00C0
+ bool unk_00C4; // 0x00C4
+ bool unk_00C5; // 0x00C5
+ uint32_t m_decor_count; // 0x00C8
+ CDecorator m_decors[10]; // 0x00CC
+ char pad[8]; // TODO!
+}; //Size: 0x15C
+static_assert(sizeof(CDynamicEntityGameStateDataNode) == 0x14C);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/entity/CEntityOrientationDataNode.hpp b/classes/src/netsync/nodes/entity/CEntityOrientationDataNode.hpp
new file mode 100644
index 0000000000..9f1c4f0de7
--- /dev/null
+++ b/classes/src/netsync/nodes/entity/CEntityOrientationDataNode.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CEntityOrientationDataNode : CSyncDataNodeFrequent
+{
+public:
+ rage::fmatrix44 m_eulers;
+}; //Size: 0x00EC
+static_assert(sizeof(CEntityOrientationDataNode) == 0x100);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/entity/CEntityScriptGameStateDataNode.hpp b/classes/src/netsync/nodes/entity/CEntityScriptGameStateDataNode.hpp
new file mode 100644
index 0000000000..ac12b91124
--- /dev/null
+++ b/classes/src/netsync/nodes/entity/CEntityScriptGameStateDataNode.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+struct CEntityScriptGameStateDataNode : CSyncDataNodeInfrequent
+{
+ bool m_fixed; //0x00C0
+ bool m_uses_collision; //0x00C1
+ bool m_completely_disabled_collision; //0x00C2
+}; //Size: 0x00C3
+static_assert(sizeof(CEntityScriptGameStateDataNode) == 0xC4);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/entity/CEntityScriptInfoDataNode.hpp b/classes/src/netsync/nodes/entity/CEntityScriptInfoDataNode.hpp
new file mode 100644
index 0000000000..0e39858f10
--- /dev/null
+++ b/classes/src/netsync/nodes/entity/CEntityScriptInfoDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "script/CGameScriptObjInfo.hpp"
+
+#pragma pack(push, 4)
+struct CEntityScriptInfoDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_has_script_info;
+ int m_pad;
+ CGameScriptObjInfo m_script_info;
+};
+static_assert(sizeof(CEntityScriptInfoDataNode) == 0x118);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/heli/CHeliControlDataNode.hpp b/classes/src/netsync/nodes/heli/CHeliControlDataNode.hpp
new file mode 100644
index 0000000000..aaaaa1ebbd
--- /dev/null
+++ b/classes/src/netsync/nodes/heli/CHeliControlDataNode.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "netsync/nodes/vehicle/CVehicleControlDataNode.hpp"
+
+#pragma pack(push, 8)
+class CHeliControlDataNode : CVehicleControlDataNode
+{
+public:
+ char m_pad[0x10]; // 0x130
+ float m_yaw_control; // 0x140
+ float m_pitch_control; // 0x144
+ float m_roll_control; // 0x148
+ float m_throttle_control; // 0x14C
+ bool m_engine_off; // 0x150
+ int m_landing_gear_state; // 0x154
+ bool m_has_landing_gear; // 0x158
+ bool m_has_vehicle_task; // 0x159
+ bool m_is_thruster_model; // 0x15A
+ float m_thruster_side_rcs_throttle; // 0x15C
+ float m_thruster_throttle; // 0x160
+ bool m_unk8; // 0x164
+};
+static_assert(sizeof(CHeliControlDataNode) == 0x168);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/heli/CHeliHealthDataNode.hpp b/classes/src/netsync/nodes/heli/CHeliHealthDataNode.hpp
new file mode 100644
index 0000000000..4369d84a04
--- /dev/null
+++ b/classes/src/netsync/nodes/heli/CHeliHealthDataNode.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalHealthDataNode.hpp"
+
+#pragma pack(push, 8)
+class CHeliHealthDataNode : CPhysicalHealthDataNode // intentionally private since the physical health node fields aren't serialized
+{
+public:
+ char m_pad[0x10]; // 0xF0
+ uint32_t m_main_rotor_health;
+ uint32_t m_rear_rotor_health;
+ bool m_can_tail_boom_break_off;
+ bool m_is_tail_boom_broken;
+ bool m_unk;
+ bool m_disable_explode_from_body_damage;
+ uint32_t m_body_health;
+ uint32_t m_petrol_tank_health;
+ uint32_t m_engine_health;
+ float m_unk_deformation_level;
+ float m_unk2_deformation_level;
+ float m_unk3_deformation_level;
+};
+static_assert(sizeof(CHeliHealthDataNode) == 0x118);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/object/CObjectCreationDataNode.hpp b/classes/src/netsync/nodes/object/CObjectCreationDataNode.hpp
new file mode 100644
index 0000000000..0058d9f3be
--- /dev/null
+++ b/classes/src/netsync/nodes/object/CObjectCreationDataNode.hpp
@@ -0,0 +1,45 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CObjectCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t unk_00C0; //0x00C0
+ uint32_t unk_00C4; //0x00C4
+ uint32_t unk_00C8; //0x00C8
+ bool unk_00CC;
+ bool unk_00CD;
+ uint16_t unk_00D0; //0x00D0
+ char pad_0xC2[14]; //0x00D2
+ rage::fvector4 m_object_orientation; //0x00E0
+ char pad_00E0[30]; //0x00F0
+ rage::fvector3 m_object_position; //0x0110
+ char pad_010C[4]; //0x011C
+ rage::fvector3 m_dummy_position; //0x011E
+ char pad_011A[20]; //0x012C
+ rage::fvector3 m_script_grab_position; //0x0140
+ char pad_013C[12]; //0x013C
+ float m_script_grab_radius; //0x0148
+ uint32_t m_created_by; //0x014C
+ uint32_t m_model; //0x0150
+ uint32_t m_frag_group_index; //0x0154
+ uint32_t m_ownership_token; //0x0158
+ uint32_t unk_015C; //0x015C
+ bool m_no_reassign; //0x0160
+ bool unk_0161; //0x0161
+ bool m_player_wants_control; //0x0162
+ bool m_has_init_physics; //0x0163
+ bool m_script_grabbed_from_world; //0x0164
+ bool m_has_frag_group; //0x0165
+ bool m_is_broken; //0x0166
+ bool m_has_exploded; //0x0167
+ bool m_keep_registered; //0x0168
+ bool unk_0169; //0x0169
+ bool unk_016A; //0x016A
+ bool unk_016B; //0x016B
+}; //Size: 0x016C
+static_assert(sizeof(CObjectCreationDataNode) == 0x17C);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedAIDataNode.hpp b/classes/src/netsync/nodes/ped/CPedAIDataNode.hpp
new file mode 100644
index 0000000000..f00893544a
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedAIDataNode.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+class CPedAIDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_relationship_group; //0x00C0
+ uint32_t m_decision_maker_type; //0x00C4
+}; //Size: 0x00C8
+static_assert(sizeof(CPedAIDataNode) == 0xC8);
diff --git a/classes/src/netsync/nodes/ped/CPedAppearanceDataNode.hpp b/classes/src/netsync/nodes/ped/CPedAppearanceDataNode.hpp
new file mode 100644
index 0000000000..80338cccc5
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedAppearanceDataNode.hpp
@@ -0,0 +1,33 @@
+#pragma once
+#include "../CPedComponents.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPedAppearanceDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t unk_0xC0[6]; //0xC0
+ uint32_t unk_0xD8[6]; //0xD8
+ class CPedComponents components; //0xF0
+ char pad_0x1B8[8]; //0x1B8
+ uint32_t unk_0x1C0; //0x1C0
+ uint8_t unk_0x1C4; //0x1C4
+ uint8_t unk_0x1C5; //0x1C5
+ char pad_0x1C6[2]; //0x1C6
+ uint32_t unk_0x1C8; //0x1C8
+ uint32_t unk_0x1CC; //0x1CC
+ uint32_t unk_0x1D0; //0x1D0
+ bool unk_0x1D4; //0x1D4
+ bool unk_0x1D5; //0x1D5
+ bool unk_0x1D6; //0x1D6
+ uint8_t unk_0x1D7; //0x1D7
+ uint16_t unk_0x1D8; //0x1D8
+ uint16_t unk_0x1DA; //0x1DA
+ uint16_t unk_0x1DC; //0x1DC
+ bool unk_0x1DE; //0x1DE
+ bool unk_0x1DF; //0x1DF
+ bool unk_0x1E0; //0x1E0
+ uint8_t unk_0x1E1; //0x1E1
+};
+static_assert(sizeof(CPedAppearanceDataNode) == 0x1E4);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedAttachDataNode.hpp b/classes/src/netsync/nodes/ped/CPedAttachDataNode.hpp
new file mode 100644
index 0000000000..4c8c087b87
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedAttachDataNode.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedAttachDataNode : CSyncDataNodeInfrequent
+{
+public:
+ rage::fvector3 m_offset; //0x00C0
+ char pad_00CC[4]; //0x00CC
+ rage::fvector4 m_orientation; //0x00D0
+ uint16_t m_attached_to; //0x00E0
+ uint16_t m_attachment_bone; //0x00E2
+ uint32_t m_attachment_flags; //0x00E4
+ float m_heading_1; //0x00E8
+ float m_heading_2; //0x00EC
+ bool m_attached; //0x00F0
+ bool unk_00F1; //0x00F1
+};
+static_assert(sizeof(CPedAttachDataNode) == 0xF4);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedComponentReservationDataNode.hpp b/classes/src/netsync/nodes/ped/CPedComponentReservationDataNode.hpp
new file mode 100644
index 0000000000..ac12d1c765
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedComponentReservationDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPedComponentReservationDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_num_peds_using_component; //0x00C0
+ uint16_t m_peds_using_component[32]; //0x00C4
+}; //Size: 0x00C8
+#pragma pack(pop)
+
+static_assert(sizeof(CPedComponentReservationDataNode) == 0x104);
diff --git a/classes/src/netsync/nodes/ped/CPedCreationDataNode.hpp b/classes/src/netsync/nodes/ped/CPedCreationDataNode.hpp
new file mode 100644
index 0000000000..dc8c9f3ea2
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedCreationDataNode.hpp
@@ -0,0 +1,28 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_pop_type; //0x00C0
+ uint32_t m_model; //0x00C4
+ uint32_t m_random_seed; //0x00C8
+ uint32_t m_max_health; //0x00CC
+ bool m_in_vehicle; //0x00D0
+ char pad_0xD1[1]; //0x00D1
+ uint16_t m_vehicle_id; //0x00D2
+ uint32_t m_vehicle_seat; //0x00D4
+ bool m_has_prop; //0x00D8
+ char pad_0xD9[3]; //0x00D9
+ uint32_t m_prop_model; //0x00DC
+ bool m_is_standing; //0x00E0
+ bool m_is_respawn_object_id; //0x00E1
+ bool m_is_respawn_flagged_for_removal; //0x00E2
+ bool m_has_attr_damage_to_player; //0x00E3
+ uint8_t m_attribute_damage_to_player; //0x00E4
+ uint32_t m_voice_hash; //0x00E8
+}; //Size: 0x00EC
+static_assert(sizeof(CPedCreationDataNode) == 0xEC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedGameStateDataNode.hpp b/classes/src/netsync/nodes/ped/CPedGameStateDataNode.hpp
new file mode 100644
index 0000000000..bd470dabe0
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedGameStateDataNode.hpp
@@ -0,0 +1,77 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,2)
+class CPedGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_weapon_component_something[12]; //0x0C0
+ uint32_t m_weapon_component_hash[12]; //0x0CC
+ uint32_t m_gadget_hash[3]; //0x0F8
+ uint32_t unk_0104; // 0x0104
+ uint32_t unk_0108; // 0x0108
+ uint32_t unk_010C; // 0x010C
+ float unk_0110; // 0x0110
+ float unk_0114; // 0x0114
+ float unk_0118; // 0x0118
+ bool unk_011C; // 0x011C
+ char pad_011D[3]; //0x011D
+ uint32_t m_arrest_state; //0x0120
+ uint32_t m_death_state; //0x0124
+ uint32_t m_weapon_hash; //0x0128
+ uint32_t m_num_weapon_components; //0x012C
+ uint32_t m_num_equiped_gadgets; //0x0130
+ uint32_t m_seat; //0x0134
+ uint32_t m_action_mode_override; //0x0138
+ uint32_t unk_013C; // 0x013C
+ uint16_t m_vehicle; //0x0140
+ uint16_t m_mount_id; //0x0142
+ uint16_t m_custodian_id; //0x0144
+ uint16_t unk_0146; // 0x0146
+ bool m_tint_index; //0x0148
+ char pad_0149; //0x0149
+ uint8_t unk_014A; // 0x014A
+ bool m_is_handcuffed; //0x014B
+ bool m_can_preform_arrest; //0x014C
+ bool m_can_preform_uncuff; //0x014D
+ bool m_can_be_arrested; //0x014E
+ bool m_is_in_custody; //0x014F
+ char pad_0150; //0x0150
+ bool m_weapon_exists; //0x0151
+ bool m_weapon_visible; //0x0152
+ bool m_weapon_has_ammo; //0x0153
+ bool m_weapon_attach_left; //0x0154
+ char pad_0155; //0x0155
+ bool m_in_seat; //0x0156
+ bool m_in_vehicle; //0x0157
+ bool m_on_mount; //0x0158
+ bool m_has_custodian_or_arrest_flags; //0x0159
+ char pad_015A; //0x015A
+ bool m_action_mode_enabled; //0x015B
+ bool m_stealth_mode_enabled; //0x015C
+ bool unk_015D; // 0x015D
+ bool unk_015E; // 0x015E
+ bool unk_015F; // 0x015F
+ bool unk_0160; // 0x0160
+ bool unk_0161; // 0x0161
+ bool unk_0162; // 0x0162
+ bool unk_0163; // 0x0163
+ bool unk_0164; // 0x0164
+ bool unk_0165; // 0x0165
+ bool unk_0166; // 0x0166
+ bool unk_0167; // 0x0167
+ bool unk_0168; // 0x0168
+ bool unk_0169; // 0x0169
+ bool unk_016A; // 0x016A
+ bool unk_016B; // 0x016B
+ bool unk_016C; // 0x016C
+ bool unk_016D; // 0x016D
+ bool unk_016E; // 0x016E
+ bool unk_016F; // 0x016F
+ bool unk_0170; // 0x0170
+ bool unk_0171; // 0x0171
+ bool unk_0172; // 0x0172
+}; //Size: 0x0174
+static_assert(sizeof(CPedGameStateDataNode) == 0x178);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedHealthDataNode.hpp b/classes/src/netsync/nodes/ped/CPedHealthDataNode.hpp
new file mode 100644
index 0000000000..2fe33ed183
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedHealthDataNode.hpp
@@ -0,0 +1,28 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include
+
+#pragma pack(push,2)
+class CPedHealthDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t unk_00C0; //0x00C0
+ uint32_t m_health; //0x00C4
+ uint32_t m_armor; //0x00C8
+ uint32_t unk_00CC; //0x00CC
+ uint32_t unk_00D0; //0x00D0
+ uint32_t m_weapon_damage_hash; //0x00D4
+ uint32_t m_hurt_end_time; //0x00D8
+ uint32_t m_weapon_damage_component; //0x00DC
+ uint16_t m_weapon_damage_entity; //0x00E0
+ bool m_has_max_health; //0x00E2
+ bool m_has_default_armor; //0x00E3
+ bool unk_00E4; //0x00E4
+ bool m_killed_with_headshot; //0x00E5
+ bool m_killed_with_melee; //0x00E6
+ char m_hurt_started; //0x00E7
+ bool unk_00E8; //0x00E8
+ bool unk_00E9; //0x00E9
+}; //Size: 0x0EA
+static_assert(sizeof(CPedHealthDataNode) == 0xEA);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedInventoryDataNode.hpp b/classes/src/netsync/nodes/ped/CPedInventoryDataNode.hpp
new file mode 100644
index 0000000000..98099fbd0b
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedInventoryDataNode.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include
+
+// todo?
+#pragma pack(push, 4)
+class CPedInventoryDataNode
+{
+public:
+ char pad_0000[5232];
+ uint32_t m_items[105];
+ uint32_t m_num_items;
+ uint32_t m_ammos[65];
+ uint32_t m_ammo_quantities[65];
+ uint32_t m_num_ammos;
+ uint8_t unk_1680[105];
+ uint8_t unk_16E9[105];
+ char pad_1680[1260];
+ bool m_infinite_ammos[65];
+ bool m_ammo_all_infinite;
+};
+static_assert(sizeof(CPedInventoryDataNode) == 0x1E24);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedMovementDataNode.hpp b/classes/src/netsync/nodes/ped/CPedMovementDataNode.hpp
new file mode 100644
index 0000000000..ae545dfbbe
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedMovementDataNode.hpp
@@ -0,0 +1,17 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedMovementDataNode : CSyncDataNodeFrequent
+{
+public:
+ bool m_has_desired_move_blend_ratio_x; //0x00C0
+ bool m_has_desired_move_blend_ratio_y; //0x00C1
+ bool unk_00C2; //0x00C2
+ float m_desired_move_blend_ratio_x; //0x00C4
+ float m_desired_move_blend_ratio_y; //0x00C8
+ float unk_00CC; //0x00CC
+ float m_desired_pitch; //0x00D0
+}; //Size: 0x00D4
+static_assert(sizeof(CPedMovementDataNode) == 0xD4);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedMovementGroupDataNode.hpp b/classes/src/netsync/nodes/ped/CPedMovementGroupDataNode.hpp
new file mode 100644
index 0000000000..bf4c90c8f4
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedMovementGroupDataNode.hpp
@@ -0,0 +1,24 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPedMovementGroupDataNode : CSyncDataNodeFrequent
+{
+public:
+ float m_unk; // 0xC0 (CTaskMotionInAutomobile+0x1EC)
+ uint32_t m_movement_task_index; // 0xC4
+ uint32_t m_movement_task_stage; // 0xC8
+ uint32_t m_movement_group; // 0xCC
+ uint32_t m_overridden_weapon_group; // 0xD0
+ uint32_t m_overridden_unk_group; // 0xD4 (SET_PED_ALTERNATE_MOVEMENT_ANIM?)
+ bool m_is_crouching; // 0xD8
+ bool m_is_stealthy; // 0xD9
+ bool m_is_strafing; // 0xDA
+ bool m_is_ragdolling; // 0xDB
+ bool m_is_ragdoll_constraint_ankle_active;// 0xDC
+ bool m_is_ragdoll_constraint_wrist_active;// 0xDD
+ char m_pad1[2]; // 0xDE
+ char m_tennis_data[0x20]; // 0xE0 TODO
+};
+static_assert(sizeof(CPedMovementGroupDataNode) == 0x100);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedOrientationDataNode.hpp b/classes/src/netsync/nodes/ped/CPedOrientationDataNode.hpp
new file mode 100644
index 0000000000..c2e5cd08e0
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedOrientationDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPedOrientationDataNode : CSyncDataNodeFrequent
+{
+public:
+ bool m_has_desired_heading_x; //000C1
+ bool m_has_desired_heading_y; //000C2
+ float m_desired_heading_x; //0x00C4
+ float m_desired_heading_y; //0x00C8
+};
+static_assert(sizeof(CPedOrientationDataNode) == 0xCC);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/ped/CPedScriptCreationDataNode.hpp b/classes/src/netsync/nodes/ped/CPedScriptCreationDataNode.hpp
new file mode 100644
index 0000000000..8d7e63e9cc
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedScriptCreationDataNode.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPedScriptCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_stay_in_car_when_jacked; //0x00C0
+}; //Size: 0x00C1
+static_assert(sizeof(CPedScriptCreationDataNode) == 0xC4);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedTaskSequenceDataNode.hpp b/classes/src/netsync/nodes/ped/CPedTaskSequenceDataNode.hpp
new file mode 100644
index 0000000000..e7353d8dba
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedTaskSequenceDataNode.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedTaskSequenceData
+{
+public:
+ int m_task_type; // 0x00
+ int m_task_data_size; // 0x04
+ char m_task_data[602]; // 0x08
+};
+static_assert(sizeof(CPedTaskSequenceData) == 0x264);
+
+class CPedTaskSequenceDataNode : CSyncDataNodeFrequent
+{
+public:
+ bool m_has_sequence; // 0xC0
+ int m_sequence_resource_id; // 0xC4
+ int m_num_tasks_in_sequence; // 0xC8
+ CPedTaskSequenceData m_task_data[10]; // 0xCC
+ int m_unk; // 0x18B4
+};
+static_assert(sizeof(CPedTaskSequenceDataNode) == 0x18B8);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedTaskSpecificDataNode.hpp b/classes/src/netsync/nodes/ped/CPedTaskSpecificDataNode.hpp
new file mode 100644
index 0000000000..4f4bb7f54d
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedTaskSpecificDataNode.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedTaskSpecificDataNode : CSyncDataNodeFrequent
+{
+public:
+ uint32_t m_task_index; //0x00C0
+ uint32_t m_task_type; //0x00C4
+ uint32_t m_buffer_size; //0x00C8
+ uint8_t m_task_data_buffer[603]; //0x00CC
+}; //Size: 0x0328
+static_assert(sizeof(CPedTaskSpecificDataNode) == 0x328);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/ped/CPedTaskTreeDataNode.hpp b/classes/src/netsync/nodes/ped/CPedTaskTreeDataNode.hpp
new file mode 100644
index 0000000000..f1bf38f4d5
--- /dev/null
+++ b/classes/src/netsync/nodes/ped/CPedTaskTreeDataNode.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPedTaskData
+{
+public:
+ int m_task_type; // 0x00
+ int m_priority; // 0x04
+ int m_tree_depth; // 0x08
+ int m_sequence_id; // 0x0C
+ bool m_active; // 0x10
+};
+static_assert(sizeof(CPedTaskData) == 0x14);
+
+class CPedTaskTreeDataNode : CSyncDataNodeFrequent
+{
+public:
+ CPedTaskData m_tasks[8]; // 0xC0
+ int m_task_bitset; // 0x160
+ int m_script_command; // 0x164
+ int m_script_command_stage; // 0x168
+};
+static_assert(sizeof(CPedTaskTreeDataNode) == 0x16C); // tree offset != size for this one
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/physical/CPhysicalAngVelocityDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalAngVelocityDataNode.hpp
new file mode 100644
index 0000000000..74a115a673
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalAngVelocityDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalAngVelocityDataNode : CSyncDataNodeFrequent
+{
+public:
+ int32_t m_ang_velocity_x; //0x00C0 Divide by 16.
+ int32_t m_ang_velocity_y; //0x00C4 Divide by 16.
+ int32_t m_ang_velocity_z; //0x00C8 Divide by 16.
+}; // 0x00CC
+static_assert(sizeof(CPhysicalAngVelocityDataNode) == 0xCC);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/physical/CPhysicalAttachDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalAttachDataNode.hpp
new file mode 100644
index 0000000000..99a3180356
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalAttachDataNode.hpp
@@ -0,0 +1,31 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPhysicalAttachDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_attached; //0x00C0
+ bool unk_00C1; //0x00C1
+ uint16_t m_attached_to; //0x00C2
+ char pad_00C4[12]; //0x00C4
+ rage::fvector3 m_offset; //0x00D0
+ char pad_00DC[4]; //0x00DC
+ rage::fvector4 m_orientation; //0x00E0
+ rage::fvector3 m_parent_offset; //0x00F0
+ char pad_00FC[4]; //0x00FC
+ uint16_t m_other_attach_bone; //0x0100
+ uint16_t m_attach_bone; //0x0102
+ uint32_t m_attach_flags; //0x0104
+ bool m_allow_initial_separation; //0x0108
+ char pad_00109[3]; //0x0109
+ float unk_010C; //0x010C
+ float unk_0110; //0x0110
+ bool unk_0114; //0x0114
+ bool unk_0115; //0x0115
+ bool m_is_cargo_vehicle; //0x0116
+}; //Size: 0x0118
+static_assert(sizeof(CPhysicalAttachDataNode) == 0x118);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/physical/CPhysicalGameStateDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalGameStateDataNode.hpp
new file mode 100644
index 0000000000..8b44ec3854
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalGameStateDataNode.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_is_visible; // 0xC0
+ bool m_flag2; // 0xC1
+ bool m_flag3; // 0xC2
+ bool m_flag4; // 0xC3
+ char m_pad; // 0xC4
+ uint32_t m_val1; // 0xC8
+ int16_t m_unk204; // 0xCC
+ bool m_unk5; // 0xCE
+}; // 0x00CC
+static_assert(sizeof(CPhysicalGameStateDataNode) == 0xD0);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/physical/CPhysicalHealthDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalHealthDataNode.hpp
new file mode 100644
index 0000000000..4b4e3b34d9
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalHealthDataNode.hpp
@@ -0,0 +1,17 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 8)
+struct CPhysicalHealthDataNode : CSyncDataNodeInfrequent
+{
+ bool unk_00C0; //0x00C0
+ bool m_has_max_health_changed; //0x00C1
+ uint32_t m_max_health; //0x00C4
+ uint32_t m_current_health; //0x00C8
+ uint16_t m_weapon_damage_entity; //0x00CC
+ uint32_t m_weapon_damage_hash; //0x00D0
+ uint64_t unk_00D8; //0x00D8
+};
+static_assert(sizeof(CPhysicalHealthDataNode) == 0xE0);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/physical/CPhysicalMigrationDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalMigrationDataNode.hpp
new file mode 100644
index 0000000000..65a9259e06
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalMigrationDataNode.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalMigrationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_unk;
+};
+static_assert(sizeof(CPhysicalMigrationDataNode) == 0xC4);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp
new file mode 100644
index 0000000000..43ca261fa7
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp
@@ -0,0 +1,36 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalScriptGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_godmode;
+ bool m_dont_load_collision;
+ bool m_freeze_on_collision_load;
+ bool m_only_damaged_by_player;
+ bool m_bullet_proof;
+ bool m_fire_proof;
+ bool m_explosion_proof;
+ bool m_collision_proof;
+ bool m_melee_proof;
+ bool m_cannot_be_damaged_by_relationship_group;
+ bool m_can_only_be_damaged_by_relationship_group;
+ bool m_smoke_proof;
+ bool m_steam_proof;
+ bool m_can_only_be_damaged_by_participants;
+ bool m_dont_reset_proofs_on_cleanup_mission;
+ bool m_no_reassign;
+ bool m_pass_control_in_tutorial;
+ bool m_visible_in_cutscene;
+ bool m_visible_in_cutscene_remain_hack;
+ bool m_pickup_by_cargobob_disabled;
+ uint32_t m_relationship_group;
+ uint32_t m_always_cloned_for_players;
+ bool m_modified_max_speed;
+ bool m_trigger_damage_event_for_zero_damage;
+ float m_max_speed;
+};
+static_assert(sizeof(CPhysicalScriptGameStateDataNode) == 0xE4); // don't know the actual size of this one
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/physical/CPhysicalScriptMigrationDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalScriptMigrationDataNode.hpp
new file mode 100644
index 0000000000..79aaa7f440
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalScriptMigrationDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalScriptMigrationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_has_data; // 0xC0
+ int m_script_participants; // 0xC4
+ uint16_t m_host_token; // 0xC8
+};
+static_assert(sizeof(CPhysicalScriptMigrationDataNode) == 0xCC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/physical/CPhysicalVelocityDataNode.hpp b/classes/src/netsync/nodes/physical/CPhysicalVelocityDataNode.hpp
new file mode 100644
index 0000000000..83ee8cb342
--- /dev/null
+++ b/classes/src/netsync/nodes/physical/CPhysicalVelocityDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPhysicalVelocityDataNode : CSyncDataNodeFrequent
+{
+public:
+ int32_t m_velocity_x; //0x00C0 Divide by 16.
+ int32_t m_velocity_y; //0x00C4 Divide by 16.
+ int32_t m_velocity_z; //0x00C8 Divide by 16.
+}; // 0x00CC
+static_assert(sizeof(CPhysicalVelocityDataNode) == 0xCC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/pickup/CPickupCreationDataNode.hpp b/classes/src/netsync/nodes/pickup/CPickupCreationDataNode.hpp
new file mode 100644
index 0000000000..f1ded50ca0
--- /dev/null
+++ b/classes/src/netsync/nodes/pickup/CPickupCreationDataNode.hpp
@@ -0,0 +1,27 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "script/CGameScriptObjInfo.hpp"
+
+#pragma pack(push, 8)
+class CPickupCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_has_placement; //0x00C0
+ char pad_00C1[7]; //0x00C1
+ CGameScriptObjInfo m_script_object_info; //0x00C8
+ uint32_t m_pickup_hash; //0x0118
+ uint32_t m_amount; //0x011C
+ uint32_t m_custom_model; //0x0120
+ uint32_t m_life_time; //0x0124
+ uint32_t m_weapon_component[12]; //0x0128
+ uint32_t m_num_weapon_components; //0x0154
+ uint32_t m_tint_index; //0x0158
+ bool m_player_gift; //0x015C
+ bool unk_015D; //0x015D
+ char pad_015E[6]; //0x015E
+ uint32_t unk_0164; //0x0164
+ bool unk_0168; //0x0168
+}; //Size: 0x0170
+static_assert(sizeof(CPickupCreationDataNode) == 0x170);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/pickup_placement/CPickupPlacementCreationDataNode.hpp b/classes/src/netsync/nodes/pickup_placement/CPickupPlacementCreationDataNode.hpp
new file mode 100644
index 0000000000..7dab6ba7e6
--- /dev/null
+++ b/classes/src/netsync/nodes/pickup_placement/CPickupPlacementCreationDataNode.hpp
@@ -0,0 +1,24 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 8)
+class CPickupPlacementCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ bool m_has_pickup_data; //0x00C0
+ char pad_00C1[15]; //0x00C1
+ rage::fvector3 m_pickup_pos; //0x00D0
+ char pad_00DC[4]; //0x00DC
+ rage::fvector4 m_pickup_orientation; //0x00E0
+ uint32_t m_pickup_type; //0x00F0
+ uint32_t m_pickup_flags; //0x00F4
+ uint32_t m_amount; //0x00F8
+ uint32_t m_custom_model; //0x00FC
+ uint32_t m_custom_regeneration_time; //0x0100
+ uint32_t m_team_permits; //0x0104
+ uint64_t *unk_struct_0108; //0x0108
+}; //Size: 0x0110
+static_assert(sizeof(CPickupPlacementCreationDataNode) == 0x110);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerAmbientModelStreamingNode.hpp b/classes/src/netsync/nodes/player/CPlayerAmbientModelStreamingNode.hpp
new file mode 100644
index 0000000000..51ae06a0d2
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerAmbientModelStreamingNode.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPlayerAmbientModelStreamingNode : CSyncDataNodeInfrequent
+{
+public:
+ int m_allowed_ped_model_start_offset; // 0xC0
+ int m_allowed_vehicle_model_start_offset; // 0xC4
+ int m_vehicle_anim_streaming_target_entrypoint; // 0xC8
+ int16_t m_vehicle_anim_streaming_target; // 0xCC
+};
+static_assert(sizeof(CPlayerAmbientModelStreamingNode) == 0xD0);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerAppearanceDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerAppearanceDataNode.hpp
new file mode 100644
index 0000000000..6338e46192
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerAppearanceDataNode.hpp
@@ -0,0 +1,93 @@
+#pragma once
+#include "../CPedComponents.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPlayerAppearanceDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t unk_0xC0[60]; //0xC0
+ class CPedComponents components; //0x1A0
+ char pad_0x268[8]; //0x268
+ uint32_t unk_0x270[6]; //0x270
+ uint32_t unk_0x288[6]; //0x288
+ char pad_0x2A0[8]; //0x2A0
+ float unk_0x2A8; //0x2A8
+ uint8_t unk_0x2AC; //0x2AC
+ uint8_t unk_0x2AD; //0x2AD
+ char pad_0x2AE[26]; //0x2AE
+ float m_shape_mix; //0x2C8
+ float m_skin_mix; //0x2CC
+ float m_third_mix; //0x2D0
+ float unk_0x2D4; //0x2D4
+ float unk_0x2D8[13]; //0x2D8
+ float unk_0x30C[13]; //0x30C
+ float unk_0x340[20]; //0x340
+ uint8_t unk_0x390[13]; //0x390
+ uint8_t unk_0x39D[13]; //0x39D
+ uint8_t unk_0x3AA[13]; //0x3AA
+ uint8_t m_shape_first; //0x3B7
+ uint8_t m_shape_second; //0x3B8
+ uint8_t m_shape_third; //0x3B9
+ uint8_t m_skin_first; //0x3BA
+ uint8_t m_skin_second; //0x3BB
+ uint8_t m_skin_third; //0x3BC
+ uint8_t unk_0x3BD[13]; //0x3BD
+ uint8_t unk_0x3CA[11]; //0x3CA
+ int16_t unk_0x3D6; //0x3D6
+ uint8_t unk_0x3D8; //0x3D8
+ uint8_t unk_0x3D9; //0x3D9
+ char pad_0x3DA[1]; //0x3DA
+ bool unk_0x3DB; //0x3DB
+ bool unk_0x3DC; //0x3DC
+ char pad_0x3DD[3]; //0x3DD
+ uint32_t unk_0x3E0; //0x3E0
+ uint32_t unk_0x3E4; //0x3E4
+ uint32_t unk_0x3E8; //0x3E8
+ uint32_t unk_0x3EC; //0x3EC
+ uint32_t unk_0x3F0; //0x3F0
+ float unk_0x3F4; //0x3F4
+ float m_blend_in_duration; //0x3F8
+ float m_blend_out_duration; //0x3FC
+ uint32_t m_anim_name_hash; //0x400
+ uint32_t m_anim_dict_index; //0x404
+ uint32_t m_anim_flags; //0x408
+ uint32_t unk_0x40C; //0x40C
+ uint32_t unk_0x410; //0x410
+ bool m_anim_task_active; //0x414
+ bool unk_0x415; //0x415
+ bool m_task_move_active; //0x416
+ bool m_mobile_phone_task_active; //0x417
+ bool m_mobile_phone_gesture_active; //0x418
+ bool unk_0x419; //0x419
+ uint32_t unk_0x41C; //0x41C
+ uint32_t m_model_hash; //0x420
+ uint32_t m_voice_hash; //0x424
+ uint32_t m_phone_mode; //0x428
+ uint32_t unk_0x42C; //0x42C
+ uint8_t m_parachute_tint_index; //0x430
+ uint8_t m_parachute_pack_tint_index; //0x431
+ uint16_t m_respawn_object; //0x432
+ bool m_has_head_blend_data; //0x434
+ bool unk_0x435; //0x435
+ bool m_has_respawn_object; //0x436
+ char pad_0x437; //0x437
+ uint32_t unk_0x438_clip_maybe; //0x438
+ uint32_t unk_0x43C; //0x43C
+ uint32_t unk_0x440; //0x440
+ bool unk_0x444; //0x444
+ bool unk_0x445; //0x445
+ bool unk_0x446; //0x446
+ uint8_t unk_0x447; //0x447
+ uint16_t unk_0x448; //0x448
+ uint16_t unk_0x44A; //0x44A
+ uint16_t unk_0x44C; //0x44C
+ bool unk_0x44E; //0x44E
+ bool unk_0x44F; //0x44F
+ bool unk_0x450; //0x450
+ uint8_t unk_0x451; //0x451
+ uint32_t unk_0x452; //0x452
+ uint32_t unk_0x456; //0x456
+};
+static_assert(sizeof(CPlayerAppearanceDataNode) == 0x46C);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerCameraDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerCameraDataNode.hpp
new file mode 100644
index 0000000000..190b669aa1
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerCameraDataNode.hpp
@@ -0,0 +1,27 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CPlayerCameraDataNode : CSyncDataNodeFrequent
+{
+public:
+ float m_free_cam_pos_x; //0x00C0
+ float m_free_cam_pos_y; //0x00C4
+ float m_free_cam_pos_z; //0x00C8
+ char pad_00CC[4]; //0x00CC
+ float m_lock_on_target_offset_x; //0x00D0
+ float m_lock_on_target_offset_y; //0x00D4
+ char pad_00D8[40]; //0x00D8
+ float m_camera_x; //0x0100
+ float m_camera_z; //0x0104
+ int16_t m_free_aim_locked_on_target; //0x0108
+ bool m_free_cam; //0x010A
+ char pad_010B[2]; //0x010B
+ bool m_has_position_offset; //0x010D
+ char pad_010E[1]; //0x010E
+ bool m_is_long_range_target; //0x010F
+ char pad_0110[48]; //0x0110
+}; //Size: 0x0140
+static_assert(sizeof(CPlayerCameraDataNode) == 0x140);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/player/CPlayerCreationDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerCreationDataNode.hpp
new file mode 100644
index 0000000000..cc430c2f2f
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerCreationDataNode.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPlayerCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_model; //0x00C0
+ uint32_t m_num_scars; //0x00C4
+ char unk_struct_0xC8[192]; //0x00C8
+ uint32_t unk_0188; //0x0188
+ char pad_018C[4]; //0x018C
+ char m_scar_struct[176]; //0x0190
+ bool unk_0240; //0x0240
+ char pad_0241[19]; //0x0241
+}; //Size: 0x0254
+static_assert(sizeof(CPlayerCreationDataNode) == 0x254);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/player/CPlayerExtendedGameStateNode.hpp b/classes/src/netsync/nodes/player/CPlayerExtendedGameStateNode.hpp
new file mode 100644
index 0000000000..7f21e765bc
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerExtendedGameStateNode.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 1)
+class CPlayerExtendedGameStateNode : CSyncDataNodeInfrequent
+{
+public:
+ float waypoint_x; //0x00C0
+ float waypoint_y; //0x00C4
+ bool unk1; //0x00C5
+ bool unk2; //0x00C6
+ bool unk3; //0x00C7
+ bool unk4; //0x00C8
+ bool unk5; //0x00C9
+ bool has_waypoint_data; //0x00CA
+ bool is_waypoint_set; //0x00CB
+};
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerGameStateDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerGameStateDataNode.hpp
new file mode 100644
index 0000000000..532a320d28
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerGameStateDataNode.hpp
@@ -0,0 +1,148 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPlayerGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_player_state; //0x00C0
+ bool m_controls_disabled_by_script; //0x00C4
+ bool m_is_max_armor_and_health_default; //0x00C5
+ bool unk_000C6; //0x00C6
+ bool m_is_spectating; //0x00C7
+ bool m_is_antagonistic_to_another_player; //0x00C8
+ bool m_never_target; //0x00C9
+ bool m_use_kinematic_physics; //0x00CA
+ bool m_has_tutorial_data; //0x00CB
+ bool m_pending_tutorial_change; //0x00CC
+ bool unk_00CD; //0x00CD
+ bool m_respawning; //0x00CE
+ bool m_will_jack_any_player; //0x00CF
+ bool m_will_jack_wanted_players; //0x00D0
+ bool m_dont_drag_from_car; //0x00D1
+ bool m_random_peds_flee; //0x00D2
+ bool m_every_ped_back_away; //0x00D3
+ bool m_has_microphone; //0x00D4
+ bool m_is_invincible; //0x00D5
+ bool unk_00D6; //0x00D6
+ bool unk_00D7; //0x00D7
+ bool m_seatbelt; //0x00D8
+ bool unk_00D9; //0x00D9
+ bool m_bullet_proof; //0x00DA
+ bool m_fire_proof; //0x00DB
+ bool m_explosion_proof; //0x00DC
+ bool m_collision_proof; //0x00DD
+ bool m_melee_proof; //0x00DE
+ bool m_water_proof; //0x00DF
+ bool m_steam_proof; //0x00E0
+ bool unk_00E1; //0x00E1
+ bool unk_00E2; //0x00E2
+ bool unk_00E3; //0x00E3
+ bool unk_00E4; //0x00E4
+ bool unk_00E5; //0x00E5
+ bool unk_00E6; //0x00E6
+ bool unk_00E7; //0x00E7
+ bool unk_00E8; //0x00E8
+ bool unk_00E9; //0x00E9
+ bool unk_00EA; //0x00EA
+ bool unk_00EB; //0x00EB
+ bool unk_00EC; //0x00EC
+ bool unk_00ED; //0x00ED
+ bool unk_00EE; //0x00EE
+ bool unk_00EF; //0x00EF
+ bool unk_00F0; //0x00F0
+ bool unk_00F1; //0x00F1
+ bool unk_00F2; //0x00F2
+ bool unk_00F3; //0x00F3
+ bool unk_00F4; //0x00F4
+ bool unk_00F5; //0x00F5
+ bool unk_00F6; //0x00F6
+ bool unk_00F7; //0x00F7
+ bool unk_00F8; //0x00F8
+ bool unk_00F9; //0x00F9
+ bool unk_00FA; //0x00FA
+ bool unk_00FB; //0x00FB
+ uint32_t unk_00FC; //0x00FC
+ uint32_t m_mobile_ring_state; //0x0100
+ int32_t m_player_team; //0x0104
+ float m_air_drag_multiplier; //0x0108
+ uint32_t m_max_health; //0x010C
+ uint32_t m_max_armor; //0x0110
+ uint32_t m_jack_speed; //0x0114
+ uint16_t m_player_is_targetable_by_team; //0x0118
+ uint32_t m_override_receive_chat; //0x011C
+ uint32_t m_override_send_chat; //0x0120
+ bool unk_0124; //0x0124
+ bool unk_0125; //0x0125
+ bool unk_0126; //0x0126
+ bool unk_0127; //0x0127
+ uint16_t m_spectating_net_id; //0x0128
+ uint8_t m_antagonistic_to_player_id; //0x012C
+ uint8_t m_tutorial_index; //0x012B
+ uint8_t m_tutorial_instance_id; //0x012C
+ char pad_012D[2]; //0x012D
+ float m_microphone_volume; //0x0130
+ uint32_t m_voice_channel; //0x0134
+ bool m_is_overriding_voice_proximity; //0x0138
+ char pad_0139[7]; //0x0139
+ float m_voice_proximity_x; //0x0140
+ float m_voice_proximity_y; //0x0144
+ float m_voice_proximity_z; //0x0148
+ float m_voice_proximity_radius_maybe; //0x014C
+ uint32_t unk_0150; //0x0150
+ uint32_t m_vehicle_weapon_index; //0x0154
+ bool m_has_vehicle_weapon_index; //0x0158
+ uint32_t m_decor_count; //0x015C
+ uint32_t m_decor_type[3]; // 0x0160
+ uint32_t m_decor_value[3]; // 0x016C
+ uint32_t m_decor_name_hash[3]; // 0x0178
+ bool m_friendly_fire_allowed; //0x0184
+ bool unk_0185; //0x0185
+ uint8_t m_current_garage_instance_index; //0x0186
+ uint8_t m_current_property_id; //0x0187
+ uint8_t unk_0188; //0x0188
+ uint8_t unk_0189; //0x0189
+ bool m_battle_aware; //0x018A
+ bool m_vehicle_jump_down; //0x018B
+ float m_weapon_defence_modifier; //0x018C
+ float m_weapon_defence_modifier_2; //0x0190
+ bool m_is_overriding_population_control_sphere; //0x0194
+ char pad_0195[11]; //0x0195
+ float m_population_control_sphere_x; //0x01A0
+ float m_population_control_sphere_y; //0x01A4
+ float m_population_control_sphere_z; //0x01A8
+ uint16_t unk_01AC; //0x01AC
+ uint16_t unk_01AE; //0x01AE
+ uint16_t unk_01B0; //0x01B0
+ bool new_01B2;
+ bool new_01B3;
+ bool pad_01B2; //0x01B2
+ bool unk_01B3; //0x01B3
+ bool m_no_collision; //0x01B4
+ bool unk_01B5; //0x01B5
+ bool unk_01B6; //0x01B6
+ bool m_super_jump; //0x01B7
+ bool unk_01B8; //0x01B8
+ bool unk_01B9; //0x01B9
+ uint16_t unk_01BA; //0x01BA
+ uint32_t unk_01BC; //0x01BC
+ float unk_01C0; //0x01C0
+ float m_weapon_damage_modifier; //0x01C4 Divisor: 0x3F800000
+ float m_melee_weapon_damage_modifier; //0x01C8 Divisor: 0x3F800000
+ float unk_01CC; //0x01CC
+ bool unk_01D0; //0x01D0
+ char pad_01D1[11]; //0x01D1
+ float unk_01E0; //0x01E0
+ float unk_01E4; //0x01E4
+ float unk_01E8; //0x01E8
+ uint32_t unk_01EC; //0x01EC
+ uint8_t unk_01F0; //0x01F0
+ uint8_t unk_01F1; //0x01F1
+ bool unk_01F2; //0x01F2
+ uint8_t unk_01F3; //0x01F3
+ bool unk_01F4; //0x01F4
+ bool unk_01F5; //0x01F5
+}; //Size: 0x01F8
+static_assert(sizeof(CPlayerGameStateDataNode) == 0x1F8);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/player/CPlayerGamerDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerGamerDataNode.hpp
new file mode 100644
index 0000000000..c1f210a6b5
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerGamerDataNode.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include
+#include "network/ClanData.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 8)
+class CPlayerGamerDataNode : CSyncDataNodeInfrequent
+{
+public:
+ ClanData m_clan_data; //0x00C0
+ bool m_need_crew_rank_sysflags; //0x0178
+ bool m_need_crew_rank_title; //0x0179
+ char m_crew_rank_title[25]; //0x017A
+ bool m_has_started_transition; //0x0193
+ bool m_has_transition_info; //0x0194
+ char m_transition_info_buffer[169]; //0x0195
+ int m_player_privilege_flags; //0x0240
+ uint32_t m_matchmaking_group; //0x0244
+ bool m_need_mute_data; //0x0248
+ int32_t m_mute_count; //0x024C
+ int32_t m_mute_talkers_count; //0x0250
+ uint32_t m_unk; //0x0254
+ int32_t m_account_id; //0x0258
+};
+static_assert(sizeof(CPlayerGamerDataNode) == 0x260);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/player/CPlayerPedGroupDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerPedGroupDataNode.hpp
new file mode 100644
index 0000000000..2f765ba919
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerPedGroupDataNode.hpp
@@ -0,0 +1,35 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+#include "ped/CPed.hpp"
+
+#pragma pack(push, 8)
+class CGroup;
+class CGroupMember
+{
+public:
+ int16_t m_net_id;
+ CPed* m_ped; // this isn't serialized
+};
+static_assert(sizeof(CGroupMember) == 0x10);
+
+class CPlayerPedGroupDataNode : CSyncDataNodeInfrequent
+{
+public:
+ char m_unused[0x10]; // 0xC0
+ CGroup* m_group; // 0xD0 (not serialized)
+ CGroupMember m_members[7]; // 0xD8
+ CGroupMember m_leader; // 0x148
+ char m_unused2[8]; // 0x158
+ float m_max_separation; // 0x160
+ char m_unused3[0xC]; // 0x164
+ int m_pop_type; // 0x170
+ bool m_needs_group_event_scan; // 0x175
+ char m_unused4[6]; // 0x176
+ int m_formation_type; // 0x17C
+ float m_formation_distance; // 0x180
+ char m_unused5[0xC]; // 0x184
+};
+static_assert(sizeof(CPlayerPedGroupDataNode) == 0x190);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerSectorPosNode.hpp b/classes/src/netsync/nodes/player/CPlayerSectorPosNode.hpp
new file mode 100644
index 0000000000..b4608c06d6
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerSectorPosNode.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPlayerSectorPosNode : CSyncDataNodeFrequent
+{
+public:
+ rage::fvector3 m_sector_pos; //0x00C0
+ bool m_is_standing_on_entity; //0x00CC
+ bool unk_00CD; //0x00CD
+ bool unk_00CE; //0x00CE
+ char pad_00CF[1]; //0x00CF
+ uint16_t m_entity_standing_on; //0x00D0
+ char pad_00D2[12]; //0x00D2
+ rage::fvector3 m_standing_on_entity_offset; //0x00E0
+ char pad_00EC[8]; //0x00EC
+ uint32_t m_stealth_noise; //0x00F4
+}; //Size: 0x00F8
+static_assert(sizeof(CPlayerSectorPosNode) == 0xF8);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/player/CPlayerWantedAndLOSDataNode.hpp b/classes/src/netsync/nodes/player/CPlayerWantedAndLOSDataNode.hpp
new file mode 100644
index 0000000000..d956e34932
--- /dev/null
+++ b/classes/src/netsync/nodes/player/CPlayerWantedAndLOSDataNode.hpp
@@ -0,0 +1,27 @@
+#pragma once
+#include
+#include "rage/vector.hpp"
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CPlayerWantedAndLOSDataNode : CSyncDataNodeInfrequent
+{
+public:
+ rage::fvector3 m_wanted_position; // 0xC0
+ int m_time_in_prev_pursuit; // 0xCC
+ rage::fvector3 m_unk_position; // 0xD0
+ int m_time_in_pursuit; // 0xDC
+ int m_wanted_level; // 0xE0
+ int m_unk_wanted_level; // 0xE4
+ int m_current_time; // 0xE8
+ int m_unk_player_bitset; // 0xEC
+ int m_pursuit_start_time; // 0xF0
+ uint8_t m_fake_wanted_level; // 0xF4
+ bool m_cops_cant_see_player; // 0xF5
+ bool m_is_evading; // 0xF6
+ bool m_pending_wanted_level; // 0xF7
+ bool m_unk3; // 0xF8
+ uint8_t m_unk_player_index; // 0xF9
+};
+static_assert(sizeof(CPlayerWantedAndLOSDataNode) == 0xFC);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp b/classes/src/netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp
new file mode 100644
index 0000000000..d72c5dc199
--- /dev/null
+++ b/classes/src/netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CGlobalFlagsDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_global_flags; //0x00C0
+ uint32_t m_ownership_token; //0x00C4
+}; //Size: 0x00C8
+static_assert(sizeof(CGlobalFlagsDataNode) == 0xC8);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/proximity_migrateable/CMigrationDataNode.hpp b/classes/src/netsync/nodes/proximity_migrateable/CMigrationDataNode.hpp
new file mode 100644
index 0000000000..2dd2ef73d5
--- /dev/null
+++ b/classes/src/netsync/nodes/proximity_migrateable/CMigrationDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CMigrationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_cloned_state; //0x00C0
+ uint32_t m_cloned_players_that_left; //0x00C4
+ uint32_t m_unsynced_nodes; //0x00C8
+}; //Size: 0x00CC
+static_assert(sizeof(CMigrationDataNode) == 0xCC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/proximity_migrateable/CSectorDataNode.hpp b/classes/src/netsync/nodes/proximity_migrateable/CSectorDataNode.hpp
new file mode 100644
index 0000000000..fd83204ab6
--- /dev/null
+++ b/classes/src/netsync/nodes/proximity_migrateable/CSectorDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 2)
+class CSectorDataNode : CSyncDataNodeFrequent
+{
+public:
+ uint16_t m_pos_x; //0xC0
+ uint16_t m_pos_y; //0xC2
+ uint16_t m_pos_z; //0xC4
+};
+static_assert(sizeof(CSectorDataNode) == 0xC6);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/proximity_migrateable/CSectorPositionDataNode.hpp b/classes/src/netsync/nodes/proximity_migrateable/CSectorPositionDataNode.hpp
new file mode 100644
index 0000000000..27ba243de9
--- /dev/null
+++ b/classes/src/netsync/nodes/proximity_migrateable/CSectorPositionDataNode.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CSectorPositionDataNode : CSyncDataNodeFrequent
+{
+public:
+ float m_sector_pos_x; //0x00C0
+ float m_sector_pos_y; //0x00C4
+ float m_sector_pos_z; //0x00C8
+}; //Size: 0x00CC
+static_assert(sizeof(CSectorPositionDataNode) == 0xCC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/task/CClonedGeneralSweepInfo.hpp b/classes/src/netsync/nodes/task/CClonedGeneralSweepInfo.hpp
new file mode 100644
index 0000000000..bfc1c39c40
--- /dev/null
+++ b/classes/src/netsync/nodes/task/CClonedGeneralSweepInfo.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+#pragma pack(push, 1)
+class CClonedGeneralSweepInfo
+{
+public:
+ char pad_0000[48]; //0x0000
+ float m_track_point[4]; //0x0030
+ uint16_t m_tracked_entity; //0x0040
+ char pad_0042[14]; //0x0042
+ float m_delta_per_second; //0x0050
+ char pad_0054[4]; //0x0054
+ uint32_t m_low_clip; //0x0058
+ uint32_t m_med_clip; //0x005C
+ uint32_t m_high_clip; //0x0060
+ uint32_t m_clip_set_id; //0x0064
+ uint32_t m_sweep_flags; //0x0068
+ float m_turn_rate; //0x006C
+};
+static_assert(sizeof(CClonedGeneralSweepInfo) == 0x70);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/task/ClonedTakeOffPedVariationInfo.hpp b/classes/src/netsync/nodes/task/ClonedTakeOffPedVariationInfo.hpp
new file mode 100644
index 0000000000..1363566b87
--- /dev/null
+++ b/classes/src/netsync/nodes/task/ClonedTakeOffPedVariationInfo.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+#include "rage/vector.hpp"
+
+#pragma pack(push, 1)
+class ClonedTakeOffPedVariationInfo
+{
+public:
+ char pad_0000[48]; //0x0000
+ rage::fvector3 m_attach_offset; //0x0030
+ char pad_003C[4]; //0x003C
+ rage::fvector3 m_velocity; //0x0040
+ char pad_004C[4]; //0x004C
+ rage::fvector3 m_attach_offset_rotation; //0x0050
+ char pad_005C[4]; //0x005C
+ uint32_t m_clip_set_id; //0x0060
+ uint32_t m_clip_id_ped; //0x0064
+ uint32_t m_clip_id_prop; //0x0068
+ int32_t m_variation_component; //0x006C
+ uint32_t m_prop_hash; //0x0070
+ int32_t m_attach_bone_tag; //0x0074
+ float m_blend_in_delta_ped; //0x0078
+ float m_blend_in_delta_prop; //0x007C
+ float m_phase_to_blend_out; //0x0080
+ float m_blend_out_delta; //0x0084
+ float m_force_to_apply; //0x0088
+ uint8_t m_variation_drawable_id; //0x008C
+ uint8_t m_variation_drawable_alt_id; //0x008D
+ char pad_008E[1]; //0x008E Drawable texture maybe?
+ uint8_t m_running_flags; //0x008F
+}; //Size: 0x0090
+static_assert(sizeof(ClonedTakeOffPedVariationInfo) == 0x90);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/train/CTrainGameStateDataNode.hpp b/classes/src/netsync/nodes/train/CTrainGameStateDataNode.hpp
new file mode 100644
index 0000000000..6d1fba256c
--- /dev/null
+++ b/classes/src/netsync/nodes/train/CTrainGameStateDataNode.hpp
@@ -0,0 +1,31 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CTrainGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_is_engine; //0x00C0
+ bool m_is_caboose; //0x00C1
+ bool m_is_mission_train; //0x00C2
+ bool m_direction; //0x00C3
+ bool m_has_passenger_carriages; //0x00C4
+ bool m_render_derailed; //0x00C5
+ bool unk_00C6; //0x00C6
+ bool unk_00C7; //0x00C7
+ uint16_t m_engine_id; //0x00C8
+ int8_t m_train_config_index; //0x00CA
+ int8_t m_carriage_config_index; //0x00CB
+ int8_t m_track_id; //0x00CC
+ char pad_00CD[3]; //0x00CD
+ float m_distance_from_engine; //0x00D0
+ float m_cruise_speed; //0x00D4
+ uint16_t m_linked_to_backward_id; //0x00D8
+ uint16_t m_linked_to_forward_id; //0x00DA
+ uint32_t m_train_state; //0x0DC
+ bool unk_00E0; //0x00E0
+ bool m_force_doors_open; //0x0E1
+}; //Size: 0x00E4
+static_assert(sizeof(CTrainGameStateDataNode) == 0xE4);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleComponentReservationDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleComponentReservationDataNode.hpp
new file mode 100644
index 0000000000..70ba08e913
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleComponentReservationDataNode.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CVehicleComponentReservationDataNode : CSyncDataNodeInfrequent
+{
+public:
+ bool m_has_component_reservations; //0x00C0
+ uint32_t m_num_peds_using_component; //0x00C4
+ uint16_t m_peds_using_component[32]; //0x00C8
+}; //Size: 0x00C8
+#pragma pack(pop)
+
+static_assert(sizeof(CVehicleComponentReservationDataNode) == 0x108);
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleControlDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleControlDataNode.hpp
new file mode 100644
index 0000000000..ea297eaef0
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleControlDataNode.hpp
@@ -0,0 +1,41 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CVehicleControlDataNode : CSyncDataNodeFrequent
+{
+public:
+ uint32_t m_num_wheels;
+ uint32_t dwordC4;
+ uint32_t m_brake_control;
+ uint32_t dwordCC;
+ uint32_t m_road_node_address;
+ bool m_kers_active;
+ bool m_bringing_vehicle_to_halt;
+ float m_halt_distance;
+ bool m_control_vertical_velocity;
+ bool m_has_suspension_data;
+ bool byteDE;
+ float m_suspension_heights[10];
+ bool byte108;
+ bool byte109;
+ bool byte10A;
+ bool byte10B;
+ bool byte10C;
+ bool byte10D;
+ bool byte10E;
+ float float110;
+ uint32_t dword114;
+ char byte118;
+ bool m_is_submarine_car;
+ char gap11A[2];
+ float m_rudder_rotation_x;
+ float m_rudder_rotation_y;
+ float m_rudder_rotation_z;
+ char byte128;
+ char byte129;
+ char pad[5];
+};
+static_assert(sizeof(CVehicleControlDataNode) == 0x130);
+#pragma pack(pop)
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleCreationDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleCreationDataNode.hpp
new file mode 100644
index 0000000000..c6542710ed
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleCreationDataNode.hpp
@@ -0,0 +1,21 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CVehicleCreationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_pop_type; //0x00C0
+ uint32_t m_random_seed; //0x00C4
+ uint32_t m_model; //0x00C8
+ uint32_t m_vehicle_status; //0x00CC
+ uint32_t m_max_health; //0x00D0
+ uint32_t m_creation_token; //0x00D4
+ bool m_car_budget; //0x00D8
+ bool m_needs_to_be_hotwired; //0x00D9
+ bool m_tires_dont_burst; //0x00DA
+ char pad_00DB[165]; //0x00DB
+}; //Size: 0x0180
+static_assert(sizeof(CVehicleCreationDataNode) == 0x180);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleDamageStatusDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleDamageStatusDataNode.hpp
new file mode 100644
index 0000000000..20740b9efa
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleDamageStatusDataNode.hpp
@@ -0,0 +1,32 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CVehicleDamageStatusDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint8_t m_bullet_counts[6]; // 0xC0
+ uint8_t m_front_damage_level; // 0xC6
+ uint8_t m_rear_damage_level; // 0xC7
+ uint8_t m_left_damage_level; // 0xC8
+ uint8_t m_right_damage_level; // 0xC9
+ uint8_t m_rear_left_damage_level; // 0xCA
+ uint8_t m_rear_right_damage_level; // 0xCB
+ uint8_t m_windows_state[8]; // 0xCC
+ float m_unk2[8]; // 0xD4
+ bool m_sirens_broken[20]; // 0xF4
+ bool m_lights_broken[20]; // 0x108
+ uint8_t m_front_bumper_state; // 0x11E
+ uint8_t m_rear_bumper_state; // 0x11F
+ uint8_t m_unk3[8]; // 0x120
+ bool m_has_damage_levels; // 0x128
+ bool m_has_broken_lights; // 0x129
+ bool m_has_broken_sirens; // 0x12A
+ bool m_has_broken_windows; // 0x12B
+ bool m_has_broken_bumpers; // 0x12C
+ bool m_has_bullets; // 0x12D
+ bool m_has_unk; // 0x12E
+}; //Size: 0x00C8
+#pragma pack(pop)
+static_assert(sizeof(CVehicleDamageStatusDataNode) == 0x130);
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleGadgetDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleGadgetDataNode.hpp
new file mode 100644
index 0000000000..73b4cd3c39
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleGadgetDataNode.hpp
@@ -0,0 +1,38 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+enum eVehicleGadgetType : uint32_t
+{
+ FORKS,
+ SEARCH_LIGHT,
+ PICK_UP_ROPE_WITH_HOOK,
+ PICK_UP_ROPE_WITH_MAGNET,
+ DIGGER_ARM,
+ HANDLER_FRAME,
+ BOMB_BAY,
+};
+
+#pragma pack(push,4)
+class CVehicleGadgetData
+{
+public:
+ eVehicleGadgetType m_gadget_type; //0x0000
+ uint8_t m_data[94]; //0x0004
+}; //Size: 0x64
+static_assert(sizeof(CVehicleGadgetData) == 0x64);
+
+class CVehicleGadgetDataNode : CSyncDataNodeFrequent
+{
+public:
+ bool m_has_parent_offset; //0x00C0
+ char pad_00C1[15]; //0x00C1
+ uint32_t m_parent_offset_x; //0x00D0
+ uint32_t m_parent_offset_y; //0x00D4
+ uint32_t m_parent_offset_z; //0x00D8
+ uint32_t m_parent_offset_w; //0x00DC
+ uint32_t m_gadget_count; //0x00E0
+ CVehicleGadgetData m_gadget_data[2]; //0x00E4
+}; //Size: 0x01AC
+static_assert(sizeof(CVehicleGadgetDataNode) == 0x1AC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleGameStateDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleGameStateDataNode.hpp
new file mode 100644
index 0000000000..a24d51b7c1
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleGameStateDataNode.hpp
@@ -0,0 +1,80 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 2)
+class CVehicleGameStateDataNode : CSyncDataNodeInfrequent
+{
+public:
+ float m_unk66;
+ float m_unk32;
+ float m_unk200;
+ float m_unk204;
+ int m_radio_station;
+ uint32_t m_lock_status;
+ uint32_t m_unk17;
+ uint32_t m_unbreakable_doors;
+ uint32_t m_open_windows;
+ uint32_t m_unk34;
+ uint8_t m_unk49[4];
+ unsigned int m_unk62_1;
+ uint32_t m_unk240;
+ uint16_t m_unk35;
+ uint16_t m_unk37[2];
+ uint16_t m_unk39;
+ uint8_t m_unk252;
+ char m_light_state;
+ uint8_t m_unk21;
+ char m_unk27[8];
+ uint8_t m_doors_open;
+ char m_door_positions[8];
+ uint32_t m_locked_players;
+ uint8_t m_is_engine_on;
+ bool m_is_engine_starting;
+ bool unk4;
+ bool m_handbrake;
+ bool m_unk6;
+ uint8_t m_siren_on;
+ bool m_unk1;
+ uint8_t m_unk13;
+ uint8_t m_unk12;
+ uint8_t m_unk14;
+ uint8_t m_unk25;
+ uint8_t m_unk26;
+ bool m_no_longer_needed;
+ uint8_t m_unk28;
+ uint8_t m_unk33;
+ uint8_t m_unk30;
+ bool m_lights_on;
+ bool m_highbeams_on;
+ char m_unk43;
+ char m_unk44;
+ bool m_unk7;
+ char m_unk29;
+ char m_unk45;
+ char m_unk46;
+ char m_unk47;
+ char m_unk48;
+ uint8_t m_unk38;
+ char m_unk51;
+ bool m_has_been_owned_by_player;
+ char m_unk53;
+ char m_unk54;
+ char m_unk55;
+ char m_unk56;
+ char m_unk57;
+ char m_unk58;
+ char m_unk61;
+ uint8_t m_unk62;
+ char m_unk63;
+ char m_unk64;
+ char m_unk67;
+ char m_unk68;
+ char m_unk138;
+ char m_unk139;
+ char m_unk59;
+ char m_unk60;
+ char pad[6];
+};
+#pragma pack(pop)
+static_assert(sizeof(CVehicleGameStateDataNode) == 0x148);
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleHealthDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleHealthDataNode.hpp
new file mode 100644
index 0000000000..228de387a0
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleHealthDataNode.hpp
@@ -0,0 +1,35 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CVehicleHealthDataNode : CSyncDataNodeInfrequent
+{
+public:
+ float m_tires_unk14[10]; //0x00C0
+ float m_tires_open_wheel_heat[10]; //0x00E8
+ bool m_tires_bursted[10]; //0x0110
+ bool m_tires_bursted_on_rim[10]; //0x011A
+ bool m_tires_unk11[10]; //0x0124
+ bool m_tires_unk12[10]; //0x012E
+ uint64_t m_unk24; //0x0138
+ int32_t m_engine_health; //0x0140
+ uint32_t m_petrol_tank_health; //0x0144
+ uint32_t m_num_tires; //0x0148
+ bool m_tires_fine; //0x014C
+ bool m_unk7; //0x014D
+ char pad_014E[1]; //0x014E
+ bool m_health_changed; //0x014F
+ uint32_t m_health; //0x0150
+ uint32_t m_body_health; //0x0154
+ uint32_t m_damage_weapon; //0x0158
+ int16_t m_damager_net_id; //0x015C
+ uint8_t m_total_repairs; //0x015E
+ uint8_t m_unk21; //0x015F
+ bool m_unk1; //0x0160
+ bool m_unk2; //0x0161
+ bool m_body_health_changed; //0x0162
+ uint32_t m_pad2; // 0x0164
+}; //Size: 0x0380
+#pragma pack(pop)
+static_assert(sizeof(CVehicleHealthDataNode) == 0x168);
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleProximityMigrationDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleProximityMigrationDataNode.hpp
new file mode 100644
index 0000000000..0346401552
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleProximityMigrationDataNode.hpp
@@ -0,0 +1,20 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CVehicleProximityMigrationDataNode : CProjectBaseSyncDataNode
+{
+public:
+ uint32_t m_max_occupants;
+ bool m_has_occupants[16];
+ int16_t m_occupants[16];
+ char pad[16];
+ bool m_override_position;
+ char pad2[8];
+ rage::fvector3 m_position;
+ rage::vector3 m_velocity;
+ char pad3[352];
+}; //Size: 0x0180
+static_assert(sizeof(CVehicleProximityMigrationDataNode) == 0x288);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleSteeringDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleSteeringDataNode.hpp
new file mode 100644
index 0000000000..525ae885ff
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleSteeringDataNode.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push, 4)
+class CVehicleSteeringNodeData : CSyncDataNodeFrequent
+{
+public:
+ float m_steering_handle; // 0xC0
+ char pad[4]; // 0xC4
+}; //Size: 0x00C8
+#pragma pack(pop)
+static_assert(sizeof(CVehicleSteeringNodeData) == 0xC8);
diff --git a/classes/src/netsync/nodes/vehicle/CVehicleTaskDataNode.hpp b/classes/src/netsync/nodes/vehicle/CVehicleTaskDataNode.hpp
new file mode 100644
index 0000000000..90d52d9035
--- /dev/null
+++ b/classes/src/netsync/nodes/vehicle/CVehicleTaskDataNode.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include "netsync/CProjectBaseSyncDataNode.hpp"
+
+#pragma pack(push,4)
+class CVehicleTaskDataNode : CSyncDataNodeInfrequent
+{
+public:
+ uint32_t m_task_type; // 0xC0
+ uint32_t m_task_data_size; // 0xC4
+ char m_task_data[255]; // 0xC8
+}; //Size: 0x0180
+static_assert(sizeof(CVehicleTaskDataNode) == 0x1C8);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/netsync/trees/CDynamicEntitySyncTreeBase.hpp b/classes/src/netsync/trees/CDynamicEntitySyncTreeBase.hpp
new file mode 100644
index 0000000000..f1d696d27b
--- /dev/null
+++ b/classes/src/netsync/trees/CDynamicEntitySyncTreeBase.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include "CEntitySyncTreeBase.hpp"
+#include "netsync/netSyncParentNode.hpp"
+
+#include "netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp"
+
+class CDynamicEntitySyncTreeBase : public CEntitySyncTreeBase
+{
+public:
+ char m_dynamic_entity_game_state_data_node[0xE28 - 0xCD8];
+};
+static_assert(sizeof(CDynamicEntitySyncTreeBase) == 0xE28);
\ No newline at end of file
diff --git a/classes/src/netsync/trees/CEntitySyncTreeBase.hpp b/classes/src/netsync/trees/CEntitySyncTreeBase.hpp
new file mode 100644
index 0000000000..45ced73026
--- /dev/null
+++ b/classes/src/netsync/trees/CEntitySyncTreeBase.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include "CProximityMigrateableSyncTreeBase.hpp"
+#include "netsync/netSyncParentNode.hpp"
+
+#include "netsync/nodes/entity/CEntityScriptInfoDataNode.hpp"
+#include "netsync/nodes/entity/CEntityScriptGameStateDataNode.hpp"
+
+class CEntitySyncTreeBase : public CProximityMigrateableSyncTreeBase
+{
+public:
+ CProjectBaseSyncParentNode m_parent_node_4[5];
+ CEntityScriptInfoDataNode m_entity_script_info_data_node;
+ CEntityScriptGameStateDataNode m_entity_script_game_state_data_node;
+};
+static_assert(sizeof(CEntitySyncTreeBase) == 0xCD8);
\ No newline at end of file
diff --git a/classes/src/netsync/trees/CPhysicalSyncTreeBase.hpp b/classes/src/netsync/trees/CPhysicalSyncTreeBase.hpp
new file mode 100644
index 0000000000..69854f3fc9
--- /dev/null
+++ b/classes/src/netsync/trees/CPhysicalSyncTreeBase.hpp
@@ -0,0 +1,29 @@
+#pragma once
+#include "CEntitySyncTreeBase.hpp"
+#include "netsync/netSyncParentNode.hpp"
+
+#include "netsync/nodes/physical/CPhysicalMigrationDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalScriptMigrationDataNode.hpp"
+#include "netsync/nodes/entity/CEntityOrientationDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalVelocityDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalAngVelocityDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalHealthDataNode.hpp"
+#include "netsync/nodes/physical/CPhysicalAttachDataNode.hpp"
+
+class CPhysicalSyncTreeBase : public CDynamicEntitySyncTreeBase
+{
+public:
+ CPhysicalMigrationDataNode m_physical_migration_data_node;
+ CPhysicalScriptMigrationDataNode m_physical_script_migration_data_node;
+ char pad_0FB8[8];
+ CEntityOrientationDataNode m_entity_orientation_data_node;
+ CPhysicalVelocityDataNode m_physical_velocity_data_node;
+ CPhysicalAngVelocityDataNode m_physical_angular_velocity_data_node;
+ char pad_1258[8];
+ CPhysicalHealthDataNode m_physical_health_data_node;
+ CPhysicalAttachDataNode m_physical_attach_data_node;
+ char pad_1458[8];
+ char m_physical_game_state_data_node[0x1530 - 0x1460]; // TODO
+ char m_physical_script_game_state_data_node[0x1620 - 0x1530]; // TODO
+};
+static_assert(sizeof(CPhysicalSyncTreeBase) == 0x1620);
\ No newline at end of file
diff --git a/classes/src/netsync/trees/CProximityMigrateableSyncTreeBase.hpp b/classes/src/netsync/trees/CProximityMigrateableSyncTreeBase.hpp
new file mode 100644
index 0000000000..38b525d814
--- /dev/null
+++ b/classes/src/netsync/trees/CProximityMigrateableSyncTreeBase.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include "netsync/CProjectSyncTree.hpp"
+#include "netsync/netSyncParentNode.hpp"
+
+#include "netsync/nodes/proximity_migrateable/CMigrationDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CSectorDataNode.hpp"
+#include "netsync/nodes/proximity_migrateable/CSectorPositionDataNode.hpp"
+
+class CProximityMigrateableSyncTreeBase : public CProjectSyncTree
+{
+public:
+ CProjectBaseSyncParentNode m_parent_node_1;
+ CProjectBaseSyncParentNode m_parent_node_2;
+ CProjectBaseSyncParentNode m_parent_node_3;
+ CMigrationDataNode m_migration_data_node;
+ CGlobalFlagsDataNode m_global_flags_data_node;
+ CSectorDataNode m_sector_data_node;
+ CSectorPositionDataNode m_sector_position_data_node;
+ char pad_0910[8];
+};
+static_assert(sizeof(CProximityMigrateableSyncTreeBase) == 0x918);
\ No newline at end of file
diff --git a/classes/src/network/CCommunications.hpp b/classes/src/network/CCommunications.hpp
new file mode 100644
index 0000000000..3dbb2ba994
--- /dev/null
+++ b/classes/src/network/CCommunications.hpp
@@ -0,0 +1,33 @@
+#pragma once
+#include
+#include "../rage/rlGamerInfo.hpp"
+
+#pragma pack(push, 1)
+class CVoiceConnection
+{
+public:
+ class rage::rlGamerInfo m_gamer_info; //0x0000
+ char pad_0098[40]; //0x00F8
+}; //Size: 0x00C0
+static_assert(sizeof(CVoiceConnection) == 0x118);
+
+class CVoice
+{
+public:
+ class CVoiceConnection m_connection_storage[32]; //0x0000
+ char pad_2300[8]; //0x2300
+ class CVoiceConnection* m_connections[32]; //0x2308
+ uint32_t m_connection_count; //0x2408
+ char pad_240C[3508]; //0x240C
+}; //Size: 0x31C0
+static_assert(sizeof(CVoice) == 0x31C0);
+
+class CCommunications
+{
+public:
+ char pad_0000[48]; //0x0000
+ class CVoice m_voice; //0x0030
+ char pad_31F0[280300]; //0x31F0
+}; //Size: 0x478DC
+static_assert(sizeof(CCommunications) == 0x478DC);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/network/CJoinRequestContext.hpp b/classes/src/network/CJoinRequestContext.hpp
new file mode 100644
index 0000000000..dae65263b8
--- /dev/null
+++ b/classes/src/network/CJoinRequestContext.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#include
+
+#pragma pack(push, 1)
+class CJoinRequestContext
+{
+public:
+ char pad_0000[40]; //0x0000
+ void* m_join_request_data; //0x0028
+ uint32_t m_join_request_size; //0x0030
+ uint8_t m_join_response_data[512]; //0x0034
+ uint32_t m_join_response_size; //0x0234
+ char pad_0238[12]; //0x0238
+}; //Size: 0x0244
+static_assert(sizeof(CJoinRequestContext) == 0x244);
+#pragma pack(pop)
diff --git a/classes/src/network/CMsgJoinResponse.hpp b/classes/src/network/CMsgJoinResponse.hpp
new file mode 100644
index 0000000000..c1fd254c55
--- /dev/null
+++ b/classes/src/network/CMsgJoinResponse.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#include
+
+#pragma pack(push, 1)
+class CMsgJoinResponse
+{
+public:
+ uint32_t m_status_code; //0x0000
+ uint32_t m_visibility_flags; //0x0004
+ bool m_can_wait_for_slot; //0x0008
+ char pad_0009[3]; //0x0009
+ bool m_is_activity_session; //0x000C
+ char pad_000D[7]; //0x000D
+ uint32_t m_network_time; //0x0014
+ char pad_0018[72]; //0x0018
+}; //Size: 0x0060
+static_assert(sizeof(CMsgJoinResponse) == 0x60);
+#pragma pack(pop)
diff --git a/classes/src/network/CMsgTextMessage.hpp b/classes/src/network/CMsgTextMessage.hpp
new file mode 100644
index 0000000000..bd2050d64a
--- /dev/null
+++ b/classes/src/network/CMsgTextMessage.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include
+
+#pragma pack(push, 1)
+class CMsgTextMessage
+{
+public:
+ char m_message[256]; //0x0000
+ uint64_t m_peer_id; //0x0100
+ bool m_is_team; //0x0108
+}; //Size: 0x0109
+static_assert(sizeof(CMsgTextMessage) == 0x109);
+#pragma pack(pop)
diff --git a/classes/src/network/CNetComplaintMgr.hpp b/classes/src/network/CNetComplaintMgr.hpp
new file mode 100644
index 0000000000..f520185ed6
--- /dev/null
+++ b/classes/src/network/CNetComplaintMgr.hpp
@@ -0,0 +1,70 @@
+#pragma once
+#include
+
+class CNetRemoteComplaint
+{
+public:
+ uint64_t m_complainer_token; //0x0000
+ uint64_t m_complainee_token; //0x0008
+ uint32_t m_flags; //0x0010
+ uint32_t m_time; //0x0014
+}; //Size: 0x0018
+static_assert(sizeof(CNetRemoteComplaint) == 0x18);
+
+class CNetComplaintMgr
+{
+public:
+ uint64_t m_host_token; //0x0000
+ uint32_t m_host_peer_id; //0x0008
+ char pad_000C[4]; //0x000C
+ void* m_net_connection_mgr; //0x0010
+ char pad_0018[64]; //0x0018
+ class rage::rlGamerHandle m_handles_in_scope[64]; //0x0058
+ uint32_t m_num_handles_in_scope; //0x0458
+ char pad_045C[4]; //0x045C
+ class CNetRemoteComplaint m_remote_complaints[64]; //0x0460
+ uint32_t m_num_remote_complaints; //0x0A60
+ char pad_0A64[4]; //0x0A64
+ uint64_t m_host_tokens_complained[64]; //0x0A68
+ uint32_t m_num_tokens_complained; //0x0C68
+ char pad_0C6C[520]; //0x0C6C
+ uint32_t m_connection_identifier; //0x0E74
+ uint32_t m_last_resend_time; //0x0E78
+ char pad_0E7C[4]; //0x0E7C
+ uint32_t m_time_to_resend; //0x0E80
+ uint32_t m_flags; //0x0E84
+ char pad_0E88[16]; //0x0E88
+
+ inline bool has_local_complaint(uint64_t host_token)
+ {
+ for (std::uint32_t i = 0; i < m_num_tokens_complained; i++)
+ if (m_host_tokens_complained[i] == host_token)
+ return true;
+
+ return false;
+ }
+
+ inline void raise_complaint(uint64_t host_token)
+ {
+ if (has_local_complaint(host_token))
+ return;
+
+ m_host_tokens_complained[m_num_tokens_complained++] = host_token;
+
+ // big::g_pointers->m_raise_network_complaint(this, host_token);
+ }
+
+ inline void remove_complaint(uint64_t host_token)
+ {
+ if (!has_local_complaint(host_token))
+ return;
+
+ for (std::uint32_t i = 0; i < m_num_tokens_complained; i++)
+ if (m_host_tokens_complained[i] == host_token)
+ m_host_tokens_complained[i] = m_host_tokens_complained[m_num_tokens_complained - 1];
+
+ m_num_tokens_complained--;
+ }
+
+}; //Size: 0x0C98
+static_assert(sizeof(CNetComplaintMgr) == 0xE98);
\ No newline at end of file
diff --git a/classes/src/network/CNetGamePlayer.hpp b/classes/src/network/CNetGamePlayer.hpp
new file mode 100644
index 0000000000..323fe67cc4
--- /dev/null
+++ b/classes/src/network/CNetGamePlayer.hpp
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "../player/CPlayerInfo.hpp"
+#include "../player/CNonPhysicalPlayerData.hpp"
+
+#include "../rage/rlSessionInfo.hpp"
+
+#include "ClanData.hpp"
+#include "netPlayer.hpp"
+
+#include
+
+#pragma pack(push, 8)
+// WARNING: most fields are out of date
+class CNetGamePlayer : public rage::netPlayer
+{
+public:
+ void* m_unk;
+ CPlayerInfo* m_player_info; //0x00A0
+ uint32_t m_matchmaking_group; //0x0008
+ bool m_is_spectating; //0x000C
+ char pad_00AD[3]; //0x000AD
+ uint64_t unk_00B0; //0x00B0
+ char unk_00B8; //0x00B8
+ char pad_00B9[3]; //0x00B9
+ uint32_t unk_00BC; //0x00BC
+ uint32_t unk_00C0; //0x00C0
+ char pad_00C4[4]; //0x00C4
+ ClanData m_clan_data; //0x00C8
+ char m_crew_rank_title[25]; //0x0180
+ bool m_is_rockstar_dev; //0x0199
+ bool m_is_rockstar_qa; //0x019A
+ bool m_is_cheater; //0x019B
+ uint32_t unk_019C; //0x019C
+ uint16_t unk_01A0; //0x01A0
+ char unk_01A2; //0x01A2
+ char pad_01A3; //0x01A3
+ uint32_t m_phone_explosion_vehicle_net_id; //0x01A4
+ uint16_t unk_01A8; //0x01A8
+ bool m_has_started_transition; //0x01AA
+ char pad_01AB[5]; //0x01AB
+ rage::rlSessionInfo m_transition_session_info; //0x01A3
+ char pad_022D[16]; //0x022D
+ void* m_unk2;
+ uint64_t unk_0230; //0x0230
+ uint64_t unk_0238; //0x0238
+ uint32_t m_mute_count; //0x0240
+ uint32_t m_mute_talkers_count; //0x0244
+ char pad_0248[5]; //0x0248
+ bool m_have_communication_privileges; //0x024D
+ uint16_t unk_024E; //0x024E
+ uint16_t unk_0250; //0x0250
+ char pad_0252[2]; //0x0252
+ uint32_t m_cheat_report_ids[20]; //0x0254
+ uint32_t m_num_cheat_reports; //0x02A4
+ uint8_t unk_02A8; //0x02A8
+ char pad_02A9[3]; //0x02A9
+ uint32_t unk_02AC; //0x02AC
+ char unk_02B0; //0x02B0
+ char pad_02B1[3]; //0x02B1
+ uint32_t unk_02B4; //0x02B4
+ uint32_t m_account_id; //0x02B4
+ uint32_t m_unk_02BC; //0x02BC
+}; //Size: 0x02C0
+static_assert(sizeof(CNetGamePlayer) == 0x330);
+#pragma pack(pop)
diff --git a/classes/src/network/CNetGamePlayerDataMsg.hpp b/classes/src/network/CNetGamePlayerDataMsg.hpp
new file mode 100644
index 0000000000..18179ed053
--- /dev/null
+++ b/classes/src/network/CNetGamePlayerDataMsg.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+
+class datBitBuffer;
+
+#pragma pack(push,8)
+namespace rage {
+ class playerDataMsg
+ {
+ public:
+ virtual ~playerDataMsg() = 0;
+ virtual int GetBufferSize() = 0;
+ virtual void Log() = 0;
+ virtual bool Serialize(datBitBuffer* buffer) = 0;
+ virtual bool Deserialize(datBitBuffer* buffer) = 0;
+
+ uint32_t m_game_version; //0x0008
+ uint32_t m_nat_type; //0x000C
+ }; //Size: 0x0010
+ static_assert(sizeof(playerDataMsg) == 0x10);
+}
+
+class CNetGamePlayerDataMsg : public rage::playerDataMsg
+{
+public:
+ uint32_t m_player_type; //0x0010
+ uint32_t m_matchmaking_group; //0x0014
+ uint32_t m_flags; //0x0018
+ uint32_t m_team; //0x001C
+ uint64_t m_crew_id; //0x0020
+ uint32_t m_aim_preference; //0x0028
+ uint16_t m_rank; //0x002C
+ uint16_t unk_002E; //0x002E
+ uint16_t unk_0030; //0x0030
+}; //Size: 0x0038
+static_assert(sizeof(CNetGamePlayerDataMsg) == 0x38);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/network/CNetworkPlayerMgr.hpp b/classes/src/network/CNetworkPlayerMgr.hpp
new file mode 100644
index 0000000000..3ccb2deb07
--- /dev/null
+++ b/classes/src/network/CNetworkPlayerMgr.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "netPlayerMgrBase.hpp"
+#include "CNetGamePlayer.hpp"
+#include "../player/CNonPhysicalPlayerData.hpp"
+
+#include
+
+#pragma pack(push, 2)
+class CNetworkPlayerMgr : public rage::netPlayerMgrBase
+{
+public:
+ CNetGamePlayer m_net_players[32]; //0x08E0
+ uint64_t unk_60E0; //0x60E0
+ uint64_t unk_60E8; //0x60E8
+ uint64_t unk_60F0; //0x60F0
+ uint64_t unk_60F8; //0x60F8
+ CNetGamePlayer m_net_players_2[32]; //0x6100
+ uint64_t unk_B900; //0xB900
+ uint64_t unk_B908; //0xB908
+ uint64_t unk_B910; //0xB910
+ uint64_t unk_B918; //0xB918
+ uint64_t unk_B920; //0xB920
+ uint64_t unk_B928; //0xB928
+ uint64_t unk_B930; //0xB930
+ uint32_t unk_B938; //0xB938
+ char pad_B93C[3]; //0xB93C
+ bool unk_B93F; //0xB93F
+ uint32_t unk_B940; //0xB940
+ uint32_t unk_B944; //0xB944
+ uint16_t unk_B948; //0xB948
+}; //Size: 0xB94A
+static_assert(sizeof(CNetworkPlayerMgr) == 0xD552);
+#pragma pack(pop)
diff --git a/classes/src/network/ChatData.hpp b/classes/src/network/ChatData.hpp
new file mode 100644
index 0000000000..dc65b0e17d
--- /dev/null
+++ b/classes/src/network/ChatData.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include
+
+class ChatData
+{
+public:
+ uint32_t m_timer_one; //0x0000
+ uint32_t m_timer_two; //0x0004
+ uint32_t m_char_count; //0x0008
+ uint32_t m_key_held_time; //0x000C
+ uint32_t m_team_label; //0x0010
+ uint8_t m_chat_open; //0x0014
+ uint8_t m_is_job; //0x0015
+ uint8_t m_disabled; //0x0016
+ uint8_t m_not_typing; //0x0017
+ uint32_t m_focus_mode; //0x0018
+ uint32_t m_chat_mode; //0x001C
+ uint32_t m_scaleform; //0x0020
+ char pad_0024[8]; //0x0024
+ char16_t m_current_text[142]; //0x002C
+ uint32_t m_hud_color; //0x0148
+ uint8_t m_hud_color_override; // 0x014C
+ char pad_014D[43]; // 0x014D
+}; //Size: 0x0178
+static_assert(sizeof(ChatData) == 0x178);
\ No newline at end of file
diff --git a/classes/src/network/ClanData.hpp b/classes/src/network/ClanData.hpp
new file mode 100644
index 0000000000..1136ba4370
--- /dev/null
+++ b/classes/src/network/ClanData.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+
+#pragma pack(push, 1)
+class ClanData
+{
+public:
+ int64_t m_clan_member_id; //0x0000
+ int64_t m_clan_id; //0x0008
+ int32_t m_clan_color; //0x0010
+ int32_t m_clan_member_count; //0x0014
+ int32_t m_clan_created_time; //0x0018
+ bool m_is_system_clan; //0x001C
+ bool m_is_clan_open; //0x001D
+ char m_clan_name[25]; //0x001E
+ char m_clan_tag[5]; //0x0037
+ char m_clan_motto[65]; //0x003C
+ char pad_007D[3]; //0x007D
+ int64_t m_clan_id_2; //0x0080
+ char m_clan_rank_name[25]; //0x0088
+ char pad_00A1[3]; //0x00A1
+ int32_t m_clan_rank_order; //0x00A4
+ int64_t m_clan_rank_flags; //0x00A8
+ char unk_00B0[8]; //0x00B0
+};
+#pragma pack(pop)
diff --git a/classes/src/network/Network.hpp b/classes/src/network/Network.hpp
new file mode 100644
index 0000000000..46c77aa125
--- /dev/null
+++ b/classes/src/network/Network.hpp
@@ -0,0 +1,288 @@
+#pragma once
+#include "../rage/rlMetric.hpp"
+#include "../security/ObfVar.hpp"
+#include "CNetComplaintMgr.hpp"
+#include "snSession.hpp"
+#include
+
+#pragma pack(push, 1)
+
+class MetricSessionMigrated : public rage::rlMetric
+{
+public:
+ char pad_0008[828]; //0x0008
+ uint32_t m_num_players; //0x0344
+}; //Size: 0x0348
+static_assert(sizeof(MetricSessionMigrated) == 0x348);
+
+class NetworkGameConfig
+{
+public:
+ char pad_0000[48]; //0x0000
+ uint32_t m_public_slots; //0x0030
+ uint32_t m_private_slots; //0x0034
+ char pad_0038[272]; //0x0038
+}; //Size: 0x0148
+static_assert(sizeof(NetworkGameConfig) == 0x148);
+
+class NetworkGameFilterMatchmakingComponent
+{
+public:
+ // do not use for actual network filters, this will break things
+ inline void SetParameter(const char* name, int index, int value)
+ {
+ std::strcpy(m_param_names[index], name);
+ m_param_mappings[index] = index;
+ m_param_values[index] = value;
+ m_enabled_params_bitset |= (1 << index);
+
+ if (m_num_parameters <= (uint32_t)index)
+ m_num_parameters++;
+ }
+
+ uint32_t m_filter_type; //0x0000
+ char m_filter_name[24]; //0x0004
+ uint32_t m_num_parameters; //0x001C
+ uint16_t m_game_mode; //0x0020
+ uint16_t m_session_type; //0x0022
+ uint32_t m_param_unk[8]; //0x0024
+ char m_param_names[8][24]; //0x0044
+ char pad_0104[4]; //0x0104
+ uint32_t m_param_mappings[8]; //0x0108
+ char pad_0128[352]; //0x0128
+ uint32_t m_param_values[8]; //0x0288
+ char pad_02A8[96]; //0x02A8
+ uint32_t m_enabled_params_bitset; //0x0308
+ char pad_030C[8]; //0x030C
+}; //Size: 0x0314
+static_assert(sizeof(NetworkGameFilterMatchmakingComponent) == 0x314);
+
+class MatchmakingAttributes
+{
+public:
+ uint32_t m_game_mode; //0x0000
+ uint32_t m_num_params; //0x0004
+ uint32_t m_param_unk[8]; //0x0008
+ char m_param_names[8][24]; //0x0028
+ uint32_t m_param_values[8]; //0x00E8
+ uint32_t m_params_bitset; //0x0108
+}; //Size: 0x010C
+static_assert(sizeof(MatchmakingAttributes) == 0x10C);
+
+class NetworkGameFilter
+{
+public:
+ virtual ~NetworkGameFilter() = default;
+ virtual void Reset() {};
+
+ uint32_t m_build_type; //0x0008
+ uint32_t m_discriminator; //0x000C
+ uint32_t m_discriminator_mapping; //0x0010
+ uint32_t m_region_mapping; //0x0014
+ uint32_t m_language_mapping; //0x0018
+ uint32_t m_mm_group_1_mapping; //0x001C
+ uint32_t m_mm_group_2_mapping; //0x0020
+ uint32_t m_activity_type_mapping; //0x0024
+ uint32_t m_activity_id_mapping; //0x0028
+ uint32_t m_activity_players_mapping; //0x002C
+ class NetworkGameFilterMatchmakingComponent m_matchmaking_component; //0x0030
+}; //Size: 0x0344
+static_assert(sizeof(NetworkGameFilter) == 0x344);
+
+class SessionInfoBackup
+{
+public:
+ class rage::rlSessionInfo m_session_info;
+ uint32_t m_unk; //0x0070
+ char pad_0074[4]; //0x0074
+ uint32_t m_flags; //0x0078
+}; //Size: 0x007C
+static_assert(sizeof(SessionInfoBackup) == 0xDC);
+
+class MatchmakingSessionResult
+{
+public:
+ class rage::rlSessionDetail m_detail;
+ char pad_03B8[24]; //0x03B8
+}; //Size: 0x03D0
+static_assert(sizeof(MatchmakingSessionResult) == 0x490);
+
+class PlayerNameMapNode
+{
+public:
+ char m_name[16]; //0x0000
+ class rage::rlGamerHandle m_handle; //0x0010
+ class PlayerNameMapNode* m_next; //0x0020
+ class PlayerNameMapNode* m_prev; //0x0028
+}; //Size: 0x0030
+static_assert(sizeof(PlayerNameMapNode) == 0x30);
+
+class JoiningPlayerNameMap
+{
+public:
+ class PlayerNameMapNode m_names[100]; //0x0000
+ char pad_12C0[40]; //0x12C0
+ uint32_t m_num_name_nodes; //0x12E8
+ char pad_12EC[796]; //0x12EC
+}; //Size: 0x1608
+static_assert(sizeof(JoiningPlayerNameMap) == 0x1608);
+
+class CNetBlacklistNode
+{
+public:
+ class rage::rlGamerHandle m_handle; //0x0000
+ bool m_block_rejoin; //0x0010
+ char pad_0011[3]; //0x0011
+ uint32_t m_added_time; //0x0014
+ class CNetBlacklistNode* m_next; //0x0018
+ class CNetBlacklistNode* m_prev; //0x0020
+}; //Size: 0x0028
+static_assert(sizeof(CNetBlacklistNode) == 0x28);
+
+class CNetBlacklist
+{
+public:
+ class CNetBlacklistNode m_nodes[16]; //0x0000
+ class CNetBlacklistNode* m_head; //0x0280
+ class CNetBlacklistNode* m_tail; //0x0288
+ uint32_t m_free_nodes; //0x0290
+ char pad_0294[4]; //0x0294
+ class CNetBlacklistNode* m_start; //0x0298
+ char pad_02A0[24]; //0x02A0
+}; //Size: 0x02B8
+static_assert(sizeof(CNetBlacklist) == 0x2B8);
+
+class RemotePlayerData
+{
+public:
+ class rage::netGamePlayerData m_data[32]; //0x0000
+ uint32_t m_count; //0x0600
+ char pad_0604[4]; //0x0604
+}; //Size: 0x0608
+static_assert(sizeof(RemotePlayerData) == 0x608);
+
+class InvitedGamer
+{
+public:
+ class rage::rlGamerHandle m_handle;
+ char pad_0010[12]; //0x0010
+ uint32_t m_flags; //0x001C
+}; //Size: 0x0020
+static_assert(sizeof(InvitedGamer) == 0x20);
+
+class InvitedGamers
+{
+public:
+ class InvitedGamer m_invited_gamers[100]; //0x0000
+ uint32_t m_num_invited_gamers; //0x0C80
+ char pad_0C84[4]; //0x0C84
+}; //Size: 0x0C88
+static_assert(sizeof(InvitedGamers) == 0xC88);
+
+class Network
+{
+public:
+ rage::rlSessionInfo m_steam_unk_session; //0x0000
+ rage::Obf32 m_num_dinput8_instances; //0x0070
+ rage::Obf32 m_last_time_dinput8_checked; //0x0080
+ class rage::snSession m_game_session; //0x00F0
+ class rage::snSession m_transition_session; //0x5578
+ char pad_AA00[16]; //0xAA00
+ class rage::snSession* m_game_session_ptr_2; //0xAA10
+ class rage::snSession* m_transition_session_ptr_2; //0xAA18
+ char pad_AA20[16]; //0xAA20
+ class rage::snSession* m_game_session_ptr; //0xAA30
+ class rage::snSession* m_transition_session_ptr; //0xAA38
+ char pad_AA40[24]; //0xAA40
+ class NetworkGameConfig m_network_game_config; //0xAA58
+ class NetworkGameConfig m_network_transition_config; //0xABA0
+ bool m_session_attributes_dirty; //0xACE8
+ char pad_ACE9[19]; //0xACE9
+ uint32_t m_session_visibility_flags; //0xACFC
+ uint32_t m_transition_visibility_flags; //0xAD00
+ char pad_AD04[68]; //0xAD04
+ class MetricSessionMigrated m_metric_session_migrated; //0xAD48
+ bool m_migrated_metric_enabled; //0xB090
+ char pad_B091[3]; //0xB091
+ uint32_t m_game_session_state; //0xB094
+ class NetworkGameFilter m_network_game_filter; //0xB098
+ char pad_B3DC[33]; //0xB3DC
+ bool m_was_invited; //0xB3FD
+ char pad_B3FE[26]; //0xB3FE TODO: the reclass file is broken
+ class rage::rlSessionInfo m_unk_session_info; //0xB408
+ char pad_B4D8[635]; //0xB4D8
+ bool m_need_host_change; //0xB753
+ char pad_B754[74316]; //0xB754
+ class rage::rlSessionDetail m_joining_session_detail; //0x1D9A0
+ class SessionInfoBackup m_last_joined_session; //0x1DE18
+ char pad_1DEF4[40]; //0x1DEF4
+ uint32_t m_current_matchmaking_group; //0x1DF1C
+ uint32_t m_matchmaking_group_max_players[5]; //0x1DF20
+ uint32_t m_num_active_matchmaking_groups; //0x1DF34
+ char pad_1DF38[8]; //0x1DF38
+ uint8_t m_matchmaking_property_id; //0x1DF40
+ uint8_t m_matchmaking_mental_state; //0x1DF41
+ char pad_1DF42[366]; //0x1DF42
+ class rage::rlMatchmakingFindResult m_game_session_matchmaking[3]; //0x1E0B0
+ char pad_2ABC0[40]; //0x2ABC0
+ class MatchmakingSessionResult m_game_matchmaking_session_results[10]; //0x2ABE8
+ char pad_2D988[308]; //0x2D988
+ uint32_t m_num_bosses; //0x2DABC
+ bool m_num_bosses_set; //0x2DAC0
+ char pad_2DAC1[7]; //0x2DAC1
+ class rage::rlGamerHandle m_transition_creator_handle; //0x2DAC8
+ char pad_2DAD8[12]; //0x2DAD8
+ bool m_is_waiting_async; //0x2DAE4
+ bool m_is_preferred_activity; //0x2DAE5
+ char pad_2DAE6[2]; //0x2DAE6
+ uint32_t m_in_progress_finish_time; //0x2DAE8
+ char pad_2DAEC[4]; //0x2DAEC
+ bool m_local_player_info_dirty; //0x2DAF0
+ char pad_2DAF1[495]; //0x2DAF1
+ class rage::rlGamerHandle m_inviter_handle; //0x2DCE0
+ class CNetComplaintMgr m_game_complaint_mgr; //0x2DCF0
+ class CNetComplaintMgr m_transition_complaint_mgr; //0x2EB88
+ char pad_2FA20[32]; //0x2FA20
+ class JoiningPlayerNameMap m_unused_joining_player_name_map; //0x2FA40
+ char pad_31048[8]; //0x31048
+ class CNetBlacklist m_blacklist; //0x31050
+ char pad_31308[8]; //0x31308
+ class InvitedGamers m_game_invited_gamers; //0x31310
+ char pad_31F98[5888]; //0x31F98
+ class SessionInfoBackup m_last_joined_transition; //0x33698
+ uint32_t m_activity_max_players; //0x33774
+ uint32_t m_activity_max_spectators; //0x33778
+ char pad_3377C[48]; //0x3377C
+ bool m_do_not_launch_from_join_as_migrated_host; //0x337AC
+ char pad_337AD[7]; //0x337AD
+ bool m_is_activity_session; //0x337B4
+ char pad_337B5[35]; //0x337B5
+ class RemotePlayerData m_remote_player_data; //0x337D8
+ char pad_33DE0[8]; //0x33DE0
+ class rage::netGamePlayerData m_local_net_game_player_data; //0x33DE8
+ char pad_33E18[608]; //0x33E18
+ class rage::rlMatchmakingFindResult m_transition_matchmaking[4]; //0x34078
+ class NetworkGameFilter m_transition_filters[4]; //0x44F38
+ char pad_45C48[20]; //0x45C48
+ uint32_t m_transition_quickmatch_group_handle_count; //0x45C5C
+ class rage::rlGamerHandle m_transition_quickmatch_group_handles[32]; //0x45C60
+ bool m_retain_activity_group; //0x45E60
+ char pad_45E61[7]; //0x45E61
+ class rage::rlSessionInfo m_transition_to_activity_session_info; //0x45E68
+ char pad_45F38[48]; //0x45F38
+ class MatchmakingSessionResult m_transition_matchmaking_session_results[10]; //0x45F68
+ char pad_48D08[8]; //0x48D08
+ class InvitedGamers m_transition_invited_gamers; //0x48D10
+ char pad_49998[16]; //0x49998
+ class rage::rlGamerHandle m_transition_to_game_handle; //0x499A8
+ class rage::rlSessionInfo m_transition_to_game_session_info; //0x499B8
+ char pad_49A88[4]; //0x49A88
+ uint32_t m_transition_to_game_session_participant_count; //0x49A8C
+ class rage::rlGamerHandle m_transition_to_game_session_participants[32]; //0x49A90
+ char pad_49C90[80]; //0x49C90
+ class rage::rlGamerHandle m_follower_handles[32]; //0x49CE0
+ uint32_t m_follower_count; //0x49EE0
+ char pad_49EE4[628]; //0x49EE4
+}; //Size: 0x38650
+static_assert(sizeof(Network) == 0x4A168);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/network/RemoteGamerInfoMsg.hpp b/classes/src/network/RemoteGamerInfoMsg.hpp
new file mode 100644
index 0000000000..7061dfccd2
--- /dev/null
+++ b/classes/src/network/RemoteGamerInfoMsg.hpp
@@ -0,0 +1,20 @@
+#pragma once
+#include
+#include "../rage/rlGamerInfo.hpp"
+#include "netConnection.hpp"
+
+#pragma pack(push, 8)
+class RemoteGamerInfoMsg
+{
+public:
+ uint64_t m_session_id; //0x0000
+ class rage::rlGamerInfo m_gamer_info; //0x0008
+ class rage::netPeerAddress m_peer_address; //0x00A0
+ uint32_t unk_0xC0; //0x00C0
+ uint32_t m_unk_struct_size; //0x00C4
+ char m_unk_struct[512]; //0x00C8 Might be bitbuffer data
+ uint32_t m_num_handles; //0x02C8
+ class rage::rlGamerHandle m_handles[32]; //0x02D0
+}; //Size: 0x04D0
+static_assert(sizeof(RemoteGamerInfoMsg) == 0x528);
+#pragma pack(pop)
diff --git a/classes/src/network/netConnection.hpp b/classes/src/network/netConnection.hpp
new file mode 100644
index 0000000000..8e12e979d7
--- /dev/null
+++ b/classes/src/network/netConnection.hpp
@@ -0,0 +1,187 @@
+#pragma once
+#include
+#include "rage/rlGamerInfoBase.hpp"
+#include "netPeerAddress.hpp"
+
+#pragma pack(push, 1)
+namespace rage
+{
+ class netConnectionManager;
+ class netConnectionPeer;
+
+ class netQueuedMessage
+ {
+ public:
+ void* m_data_buffer;
+ void* qword8;
+ void* qword10;
+ void* qword18;
+ rage::netQueuedMessage* m_next;
+ void* qword28;
+ char gap30[8];
+ int m_creation_time;
+ int m_last_send_time;
+ int m_resend_count;
+ char gap44[4];
+ int dword48;
+ uint16_t word4C;
+ char byte4E;
+ };
+ static_assert(sizeof(netQueuedMessage) == 0x4F);
+
+ class netMessageQueue
+ {
+ public:
+ rage::netQueuedMessage* m_first;
+ rage::netQueuedMessage* m_last;
+ uint64_t m_count;
+ };
+
+ class netPackedMessage
+ {
+ public:
+ void* m_data_buffer;
+ void* m_allocator;
+ void* qword10;
+ void* qword18;
+ };
+
+ class netPackedMessageQueue
+ {
+ public:
+ rage::netPackedMessage* m_first;
+ rage::netPackedMessage* m_last;
+ uint64_t m_count;
+ };
+
+ class netConnection
+ {
+ public:
+ class InFrame
+ {
+ public:
+ enum class EventType
+ {
+ ConnectionClosed = 3,
+ FrameReceived = 4,
+ BandwidthExceeded = 6,
+ OutOfMemory = 7
+ };
+
+ virtual ~InFrame() = default;
+
+ virtual void destroy() = 0;
+ virtual EventType get_event_type() = 0;
+ virtual uint32_t _0x18() = 0;
+
+ uint32_t m_timestamp; //0x0008
+ char pad_0008[52]; //0x000C
+ uint32_t m_msg_id; //0x0040
+ uint32_t m_connection_identifier; //0x0044
+ InFrame* m_this; //0x0048
+ uint32_t m_peer_id; //0x0050
+ char pad_0050[44]; //0x0058
+ uint32_t m_length; //0x0080
+ char pad_007C[4]; //0x0084
+ void* m_data; //0x0088
+ };
+ static_assert(sizeof(rage::netConnection::InFrame) == 0x90);
+
+ char gap0[8];
+ rage::netConnectionPeer* m_connection_peer;
+ int m_msg_id;
+ uint32_t m_connection_id;
+ void* m_allocator;
+ uint32_t m_connection_state;
+ uint32_t m_last_send_time;
+ uint32_t m_last_receive_time;
+ uint32_t m_num_failed_messages;
+ char gap30[8];
+ uint32_t m_timeout_reason;
+ uint32_t dword3C;
+ uint32_t m_timeout;
+ uint32_t dword44;
+ uint32_t m_resend_threshold;
+ char gap4C[4];
+ rage::netMessageQueue m_reliables_resend_queue;
+ rage::netMessageQueue m_normal_message_queue;
+ rage::netQueuedMessage* m_unacked_reliable_message_list;
+ int m_unacked_reliable_message_count;
+ char gap8C[36];
+ netConnectionManager* m_net_connection_mgr;
+ char gapB8[8];
+ uint32_t dwordC0;
+ int16_t m_msg_counter;
+ int16_t wordC6;
+ char gapC8[2];
+ int16_t m_last_reliable_msg_counter;
+ char m_flags;
+ char gapCD[3];
+ int m_failed_allocation_size;
+ int32_t m_failed_allocations;
+ rage::netConnection* m_next;
+ char gapE0[208];
+ int m_flags2;
+ char gap1B4[69];
+ };
+ static_assert(sizeof(netConnection) == 0x1F9);
+
+ class netConnectionQueue
+ {
+ public:
+ rage::netConnection* m_first;
+ rage::netConnection* m_last;
+ uint64_t m_count;
+ };
+
+ class netConnectionPeer
+ {
+ public:
+ rage::netConnection* m_connections_by_id[16];
+ rage::netConnectionQueue m_net_connection_queue;
+ rage::netPackedMessageQueue m_packed_message_queue;
+ void* qwordB0;
+ char byteB8;
+ char gapB9[3];
+ int intBC;
+ uint32_t dwordC0;
+ char gapC4[4];
+ void* qwordC8;
+ rage::netPeerAddress m_relay_address;
+ rage::rlGamerInfoBase m_gamer_info;
+ char gap1B0[24];
+ uint32_t dword1C8;
+ char gap1CC[28];
+ uint32_t m_security_id;
+ char gap1EC[28];
+ void* qword208;
+ char gap210[24];
+ rage::netPeerAddress m_peer_address;
+ rage::netConnectionPeer* m_next;
+ char gap250[8];
+ int m_time_until_next_batch;
+ int m_empty_batch_interval;
+ uint32_t m_time_until_timeout;
+ int m_last_msg_process_time;
+ int gap268;
+ void* qword26C;
+ char gap274[4];
+ void* qword278;
+ char gap280[24];
+ void* qword298;
+ char gap2A0[64];
+ uint32_t m_peer_id;
+ char byte2E4;
+ char more[51];
+ int gap318;
+ char gap31C[24];
+ int m_num_encryption_attempts;
+ char gap338[60];
+ int m_num_messages_batched;
+ int m_num_reliable_messages_batched;
+ int m_num_resent_reliable_messages_batched;
+ char gap380[145];
+ };
+ static_assert(sizeof(netConnectionPeer) == 0x411);
+}
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/network/netObject.hpp b/classes/src/network/netObject.hpp
new file mode 100644
index 0000000000..08f44677cd
--- /dev/null
+++ b/classes/src/network/netObject.hpp
@@ -0,0 +1,133 @@
+#pragma once
+
+#include
+#include "../netsync/netSyncTree.hpp"
+#include "../base/atRTTI.hpp"
+
+class CObject;
+namespace rage
+{
+ class netObject
+ {
+ public:
+ int16_t m_object_type; //0x0008
+ int16_t m_object_id; //0x000A
+ char pad_000C[61]; //0x000C
+ int8_t m_owner_id; //0x0049
+ int8_t m_control_id; //0x004A
+ int8_t m_next_owner_id; //0x004B
+ bool m_is_remote; //0x004C
+ bool m_wants_to_delete; //0x004D
+ char pad_004E[1]; //0x004E
+ bool m_should_not_be_delete; //0x004F
+
+ DEFINE_RAGE_RTTI(rage::netObject)
+
+ virtual void mov1() = 0; // 0x38
+ virtual void mov2() = 0; // 0x40
+
+ virtual void m_8() = 0; // 0x48
+ virtual void m_10() = 0; // 0x50
+ virtual void m_18() = 0; // 0x58
+ virtual void* m_20() = 0; // 0x60
+ virtual void m_28() = 0; // 0x68
+ virtual netSyncTree* GetSyncTree() = 0; // 0x70
+ virtual void m_38() = 0; // 0x78
+ virtual void m_40() = 0; // 0x80
+ virtual void m_48() = 0;
+ virtual void m_50() = 0;
+ virtual void m_58() = 0;
+ virtual void m_60() = 0;
+ virtual void m_68() = 0;
+ virtual void m_70() = 0;
+ virtual void m_78() = 0;
+ virtual CObject* GetGameObject() = 0;
+ virtual void m_88() = 0;
+ virtual void m_90() = 0;
+ virtual void m_98() = 0;
+ virtual int GetObjectFlags() = 0;
+ virtual void m_A8() = 0;
+ virtual void m_B0() = 0;
+ virtual void m_B8() = 0;
+ virtual void m_C0() = 0;
+ virtual void m_C8() = 0;
+ virtual int GetSyncFrequency() = 0;
+ virtual void m_D8() = 0;
+ virtual void m_E0() = 0;
+ virtual void m_E8() = 0;
+ virtual void m_F0() = 0;
+ virtual void m_F8() = 0;
+ virtual void Update() = 0;
+ virtual bool m_108_1604() = 0; // added in 1604
+ virtual void m_108() = 0;
+ virtual void m_110() = 0;
+ virtual void m_118() = 0;
+ virtual void m_120() = 0;
+ virtual void m_128() = 0;
+ virtual void m_130() = 0;
+ virtual void m_138() = 0;
+ virtual void m_140() = 0;
+ virtual void m_148() = 0;
+ virtual void m_150() = 0;
+ virtual bool m_158(void* player, int type, int* outReason) = 0;
+ virtual void m_160() = 0;
+ virtual bool m_168(int* outReason) = 0;
+ virtual void m_170() = 0;
+ virtual void m_178() = 0;
+ virtual void m_180() = 0;
+ virtual void m_188() = 0;
+ virtual void m_190() = 0;
+ virtual void m_198() = 0;
+ virtual void m_1A0() = 0;
+ virtual void m_1A8() = 0;
+ virtual void m_1B0() = 0;
+ virtual void m_1B8() = 0;
+ virtual void m_1C0() = 0;
+ virtual void m_1C8() = 0;
+ virtual void m_1D0() = 0;
+ virtual void m_1D8() = 0;
+ virtual void m_1E0() = 0;
+ virtual void m_1E8() = 0;
+ virtual void m_1F0() = 0;
+ virtual void m_1F8() = 0;
+ virtual void m_200() = 0;
+ virtual void m_208() = 0;
+ virtual void m_210() = 0;
+ virtual void m_218() = 0;
+ virtual void m_220() = 0;
+ virtual void m_228() = 0;
+ virtual void m_230() = 0;
+ virtual void m_238() = 0;
+ virtual void m_240() = 0;
+ virtual void m_248() = 0;
+ virtual void m_250() = 0;
+ virtual void m_258() = 0;
+ virtual void m_260() = 0;
+ virtual void m_268() = 0;
+ virtual void m_270() = 0;
+ virtual void m_278() = 0;
+ virtual void m_280() = 0;
+ virtual void m_288() = 0;
+ virtual void m_290() = 0;
+ virtual void m_298() = 0;
+ virtual void m_2A0() = 0;
+ virtual void m_2A8() = 0;
+ virtual void m_2B0() = 0;
+ virtual void m_2B8() = 0;
+ virtual void m_2C0() = 0;
+ virtual void m_2C8() = 0;
+ virtual void m_2D0() = 0;
+ virtual void m_2D8() = 0;
+ virtual void m_2E0() = 0;
+ virtual void m_2E8() = 0;
+ virtual void m_2F0() = 0;
+ virtual void m_2F8() = 0;
+ virtual void m_300() = 0;
+ virtual void m_308() = 0;
+ virtual void m_310() = 0;
+ virtual void m_318() = 0;
+ virtual void m_320() = 0;
+ virtual void UpdatePendingVisibilityChanges() = 0;
+ }; //Size: 0x0050
+ static_assert(sizeof(netObject) == 0x50);
+}
diff --git a/classes/src/network/netPeerAddress.hpp b/classes/src/network/netPeerAddress.hpp
new file mode 100644
index 0000000000..0127e58ac4
--- /dev/null
+++ b/classes/src/network/netPeerAddress.hpp
@@ -0,0 +1,32 @@
+#pragma once
+#include
+
+union netAddress {
+ uint32_t m_packed; //0x0000
+ struct {
+ uint8_t m_field4; //0x0000
+ uint8_t m_field3; //0x0001
+ uint8_t m_field2; //0x0002
+ uint8_t m_field1; //0x0003
+ };
+}; //Size: 0x0004
+static_assert(sizeof(netAddress) == 0x04);
+
+namespace rage
+{
+#pragma pack(push, 4)
+ class netPeerAddress
+ {
+ public:
+ netAddress m_internal_ip; //0x0000
+ uint16_t m_internal_port; //0x0004
+ netAddress m_external_ip; //0x0008
+ uint16_t m_external_port; //0x000C
+ uint64_t m_peer_id; //0x0010
+ netAddress m_relay_address; //0x0018
+ uint16_t m_relay_port; //0x001C
+ uint8_t m_connection_type; //0x001E
+ };
+ static_assert(sizeof(netPeerAddress) == 0x20);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/network/netPlayer.hpp b/classes/src/network/netPlayer.hpp
new file mode 100644
index 0000000000..30b29373a8
--- /dev/null
+++ b/classes/src/network/netPlayer.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "../rage/rlGamerInfo.hpp"
+#include "../player/CNonPhysicalPlayerData.hpp"
+
+namespace rage
+{
+#pragma pack(push, 8)
+ class netPlayer
+ {
+ public:
+ virtual void* _0x00();
+ virtual void* _0x08();
+ virtual uint32_t _0x10();
+ virtual netPlayer* _0x18(void*);
+ virtual bool _0x20(void*);
+ virtual bool _0x28(void**);
+ virtual void destructor();
+ virtual void reset();
+ virtual bool is_valid();
+ virtual const char* get_name();
+ virtual void _0x50();
+ virtual bool is_host();
+ virtual rage::rlGamerInfo* get_net_data();
+ virtual void _0x68();
+
+ char pad_0008[8]; //0x0008
+ CNonPhysicalPlayerData* m_non_physical_player; //0x0010
+ uint32_t m_msg_id; //0x0018
+ char pad_001C[4]; //0x001C
+ uint8_t m_active_id; //0x0020
+ uint8_t m_player_id; //0x0021
+ char pad_0022[3]; //0x0022
+ uint16_t m_complaints; //0x0026
+ char pad_0027[17]; //0x0028
+ class CNetGamePlayer* m_unk_net_player_list[10]; //0x0040
+ char pad_0090[4]; //0x0090
+ uint64_t pad_0098; //0x0098
+ }; //Size: 0x00A0
+ static_assert(sizeof(netPlayer) == 0xA0);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/network/netPlayerMgrBase.hpp b/classes/src/network/netPlayerMgrBase.hpp
new file mode 100644
index 0000000000..12226709ce
--- /dev/null
+++ b/classes/src/network/netPlayerMgrBase.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "CNetGamePlayer.hpp"
+#include "CNetGamePlayerDataMsg.hpp"
+#include "../player/CNonPhysicalPlayerData.hpp"
+
+#include
+
+namespace rage
+{
+#pragma pack(push, 8)
+ class netPlayerMgrBase
+ {
+ public:
+ virtual ~netPlayerMgrBase() = default;
+ virtual void Initialize() = 0;
+ virtual void Shutdown() = 0;
+ virtual void unk_0x18() = 0;
+ virtual CNetGamePlayer* AddPlayer_raw(rage::rlGamerInfo* gamer_info, uint32_t a2, CNetGamePlayerDataMsg* player_data, CNonPhysicalPlayerData* non_physical_player_data) = 0;
+ virtual void RemovePlayer(CNetGamePlayer* net_game_player) = 0;
+ virtual void UpdatePlayerListsForPlayer(CNetGamePlayer* net_game_player) = 0;
+ virtual CNetGamePlayer* AddPlayer(rage::rlGamerInfo* gamer_info, uint32_t a3, CNetGamePlayerDataMsg* player_data, CNonPhysicalPlayerData* non_physical_player_data) = 0;
+
+ char pad_0008[8]; //0x0008
+ uint64_t* m_network_bandwidth_manager; //0x0010
+ char pad_0018[216]; //0x0018
+ CNetGamePlayer* m_local_net_player; //0x00E8
+ char pad_00F0[144]; //0x00F0
+ CNetGamePlayer* m_player_list[32]; //0x0180
+ uint16_t m_player_limit; //0x0280
+ char pad_0282[10]; //0x0282
+ uint16_t m_player_count; //0x028C
+ char pad_0290[1618]; //0x0290
+ }; //Size: 0x08E0
+ static_assert(sizeof(netPlayerMgrBase) == 0x8E8);
+#pragma pack(pop)
+}
diff --git a/classes/src/network/netTime.hpp b/classes/src/network/netTime.hpp
new file mode 100644
index 0000000000..c18e0e96a7
--- /dev/null
+++ b/classes/src/network/netTime.hpp
@@ -0,0 +1,40 @@
+#pragma once
+#include
+
+namespace rage
+{
+ class netConnectionManager;
+}
+
+namespace rage
+{
+ class netTime
+ {
+ public:
+ virtual ~netTime() = default;
+
+ netConnectionManager* m_net_connection_mgr; //0x0008
+ uint32_t m_host_peer_id; //0x0010
+ uint32_t m_time_token; //0x0014
+ uint32_t m_time_offset; //0x0018
+ char pad_001C[72]; //0x001C
+ uint32_t m_failed_sync_counter; //0x0064
+ uint32_t m_last_sync_id_sent; //0x0068
+ uint32_t m_last_sync_id_received; //0x006C
+ uint32_t m_role_flags; //0x0070
+ uint32_t m_connection_identifier; //0x0074
+ uint32_t m_time; //0x0078
+ uint32_t m_calculation_flags; //0x007C
+ }; //Size: 0x0080
+ static_assert(sizeof(netTime) == 0x80);
+
+ struct netTimeSyncMsg
+ {
+ int action;
+ int counter;
+ int token;
+ int timestamp;
+ int increment;
+ };
+ static_assert(sizeof(netTimeSyncMsg) == 0x14);
+}
\ No newline at end of file
diff --git a/classes/src/network/snConnectToPeerTask.hpp b/classes/src/network/snConnectToPeerTask.hpp
new file mode 100644
index 0000000000..8edc25bf88
--- /dev/null
+++ b/classes/src/network/snConnectToPeerTask.hpp
@@ -0,0 +1,21 @@
+#pragma once
+#include
+
+namespace rage
+{
+ class snConnectToPeerTaskData
+ {
+ public:
+ int m_unk;
+ int m_reason;
+ uint64_t m_session_token;
+ };
+
+ class snConnectToPeerTaskResult
+ {
+ public:
+ char pad[0x10]{};
+ int m_peer_id;
+ char pad2[0x400]{};
+ };
+}
\ No newline at end of file
diff --git a/classes/src/network/snSession.hpp b/classes/src/network/snSession.hpp
new file mode 100644
index 0000000000..27621513c7
--- /dev/null
+++ b/classes/src/network/snSession.hpp
@@ -0,0 +1,195 @@
+#pragma once
+
+#include "../rage/rlGamerInfo.hpp"
+#include "../rage/rlSessionInfo.hpp"
+
+#pragma pack(push, 1)
+namespace rage
+{
+ class netConnectionManager;
+ class sysMemAllocator;
+
+ class snPlayer
+ {
+ public:
+ uint64_t m_msg_id; //0x0000
+ class rage::rlGamerInfo m_player_data; //0x0008
+ char pad_00F8[8]; //0x00F8
+ }; //Size: 0x0100
+ static_assert(sizeof(rage::snPlayer) == 0x100);
+
+ class snPeer
+ {
+ public:
+ class rage::rlGamerInfo m_peer_data; //0x0000
+ char pad_0098[40]; //0x0098
+ }; //Size: 0x00C0
+ static_assert(sizeof(rage::snPeer) == 0x118);
+
+ class rlRemoteGamer
+ {
+ public:
+ rage::rlGamerHandle m_handle;
+ char pad_0010[4]; //0x0010
+ uint32_t m_timeout_time; //0x0014
+ uint32_t m_time_unk; //0x0018
+ char pad_001C[4]; //0x001C
+ }; //Size: 0x0020
+ static_assert(sizeof(rage::rlRemoteGamer) == 0x20);
+
+
+ class rlSession
+ {
+ public:
+ char pad_0008[248]; //0x0008
+ class rage::rlSessionInfo m_session_info; //0x0100
+ char pad_01D0[296]; //0x01D0
+ uint64_t m_session_id; //0x02F8
+ char pad_0300[1136]; //0x0300
+
+ virtual ~rlSession() = default;
+ }; //Size: 0x0770
+ static_assert(sizeof(rage::rlSession) == 0x770);
+
+ class rlSessionDetail
+ {
+ public:
+ class rage::rlGamerInfoBase m_base_gamer_info;
+ char pad_0060[8]; //0x0060
+ class rage::rlSessionInfo m_session_info; //0x0068
+ char pad_00D8[14]; //0x00D8
+ uint16_t m_session_type; //0x00E6
+ char pad_00E8[324]; //0x00E8
+ uint32_t m_player_count; //0x022C
+ uint32_t m_unk_player_count; //0x0230
+ char pad_0234[2]; //0x0234
+ int16_t m_unk_pos_x; //0x0236
+ int16_t m_unk_pos_y; //0x0238
+ int16_t m_unk_pos_z; //0x023A
+ uint8_t m_matchmaking_property_ids[32]; //0x023C
+ char pad_025C[2]; //0x025C
+ uint16_t m_rank; //0x025E
+ char pad_0260[1]; //0x0260
+ uint8_t m_mental_state; //0x0261
+ char pad_0262[21]; //0x0262
+ uint8_t m_population_density; //0x0277
+ char pad_0278[320]; //0x0278
+ }; //Size: 0x03CA
+ static_assert(sizeof(rlSessionDetail) == 0x478);
+
+
+ class rlMatchmakingFindResult
+ {
+ public:
+ class rage::rlSessionDetail m_result_session_details[15]; //0x0000
+ char pad_37C8[168]; //0x37C8
+ }; //Size: 0x3870
+ static_assert(sizeof(rage::rlMatchmakingFindResult) == 0x43B0);
+
+ class netGamePlayerData
+ {
+ public:
+ class rlGamerHandle m_handle;
+ bool m_is_activity_spectator; //0x0010
+ char pad_0011[7]; //0x0011
+ uint64_t m_crew_id; //0x0018
+ uint16_t m_rank; //0x0020
+ uint16_t m_debug_unk; //0x0022
+ char pad_0024[4]; //0x0024
+ uint32_t m_nat_type; //0x0028
+ bool m_is_rockstar_dev; //0x002C
+ char pad_002D[3]; //0x002D
+ }; //Size: 0x0030
+ static_assert(sizeof(rage::netGamePlayerData) == 0x30);
+
+
+ class snSession
+ {
+ public:
+ uint64_t m_memory_allocator; //0x0000
+ char pad_0008[64]; //0x0008
+ rage::netConnectionManager* m_net_connection_mgr; //0x0048
+ char pad_0050[48]; //0x0050
+ class rage::rlSession m_rline_session; //0x0080
+ class rage::snPlayer m_local_player; //0x07F0
+ uint64_t m_host_token; //0x08F0
+ char pad_08F8[144]; //0x08F8
+ class rage::snPeer m_peer_storage[32]; //0x0988
+ char pad_2C88[24]; //0x2C88
+ class rage::snPeer* m_peers[32]; //0x2CA0
+ uint32_t m_peer_count; //0x2DA0
+ char pad_2DA4[4]; //0x2DA4
+ class rage::snPlayer m_player_storage[32]; //0x2DA8
+ char pad_4DA8[24]; //0x4DA8
+ class rage::snPlayer* m_players[32]; //0x4DC0
+ int32_t m_player_count; //0x4EC0
+ char pad_4EC4[4]; //0x4EC4
+ class rage::rlRemoteGamer m_remote_gamers[32]; //0x4EC8
+ uint32_t m_num_remote_gamers; //0x52C8
+ bool m_player_joining; //0x52CC
+ char pad_52CD[107]; //0x52CD
+ uint32_t m_connection_identifier; //0x5338
+ char pad_533C[4]; //0x533C
+ uint32_t m_profile_index; //0x5340
+ char m_token_key[64]; //0x5344
+ char m_id_key[64]; //0x5384
+ char m_info_key[64]; //0x53C4
+ char m_host_key[64]; //0x5404
+ char m_join_key[64]; //0x5444
+ char pad_5484[4]; //0x5484
+
+ inline bool is_host()
+ {
+ return m_local_player.m_player_data.m_host_token == m_host_token;
+ }
+
+ inline snPlayer* get_player_by_token(uint64_t token)
+ {
+ for (std::uint32_t i = 0; i < m_player_count; i++)
+ {
+ if (m_players[i]->m_player_data.m_host_token == token)
+ {
+ return m_players[i];
+ }
+ }
+
+ return nullptr;
+ }
+
+ inline snPeer* get_peer_by_rockstar_id(uint64_t rid)
+ {
+ for (uint32_t i = 0; i < m_peer_count; i++)
+ {
+ if (m_peers[i]->m_peer_data.m_gamer_handle_2.m_rockstar_id == rid)
+ {
+ return m_peers[i];
+ }
+ }
+
+ return nullptr;
+ }
+
+ }; //Size: 0x3E70
+ static_assert(sizeof(rage::snSession) == 0x5488);
+
+ class snMsgRemoveGamersFromSessionCmd
+ {
+ public:
+ uint64_t m_session_id; //0x0000
+ rage::rlGamerHandle m_handles[32]; //0x0008
+ int32_t m_unk = -1; //0x208
+ uint32_t m_num_peers; //0x20C
+ }; //Size: 0x0110
+ static_assert(sizeof(rage::snMsgRemoveGamersFromSessionCmd) == 0x210);
+}
+
+class SessionSortEntry
+{
+public:
+ class rage::rlSessionDetail* m_session_detail; //0x0000
+ char pad_0008[4]; //0x0008
+ float m_score; //0x000C
+ char pad_0010[8]; //0x0010
+}; //Size: 0x0018
+static_assert(sizeof(SessionSortEntry) == 0x18);
+#pragma pack(pop)
diff --git a/classes/src/ped/CPed.hpp b/classes/src/ped/CPed.hpp
new file mode 100644
index 0000000000..a24b2d11e2
--- /dev/null
+++ b/classes/src/ped/CPed.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "../vehicle/CVehicle.hpp"
+#include "../player/CPlayerInfo.hpp"
+#include "CPedModelInfo.hpp"
+#include "CPedWeaponManager.hpp"
+#include "CPedInventory.hpp"
+#include "../entities/fwEntity.hpp"
+#include "../rage/vector.hpp"
+#include "CPedIntelligence.hpp"
+#include "CPedBoneInfo.hpp"
+
+#include
+#include
+
+#pragma pack(push, 1)
+class CPed : public rage::CPhysical
+{
+public:
+ char gap2EC[20];
+ rage::fvector3 m_velocity; //0x0300
+ char pad_030C[260]; //0x030C
+ class CPedBoneInfo m_bone_info[9]; //0x0410
+ char pad_04A0[2160]; //0x04A0
+ class CVehicle *m_vehicle; //0x0D10
+ char pad_0D18[896]; //0x0D18
+ uint32_t m_ped_type; //0x1098
+ char pad_109C[4]; //0x109C
+ class CPedIntelligence* m_ped_intelligence; //0x10A0
+ class CPlayerInfo *m_player_info; //0x10A8
+ class CPedInventory* m_inventory; //0x10B0
+ class CPedWeaponManager *m_weapon_manager; //0x10B8
+ char pad_10C0[892]; //0x10C0
+ uint8_t m_seatbelt; //0x143C
+ char pad_143D[13]; //0x143D
+ uint8_t m_can_switch_weapon; //0x144A
+ uint8_t m_ped_task_flag; //0x144B
+ char pad_144C[4]; //0x144C
+ uint8_t m_forced_aim; //0x1450 m_forced_aim ^= (m_forced_aim ^ -(char)toggle) & 0x20;
+ char pad_1451[187]; //0x1451
+ float m_armor; //0x150C
+ float unk_health_threshold; //0x1510
+ float m_fatigued_health_threshold; //0x1514
+ float m_injured_health_threshold; //0x1518
+ float m_dying_health_threshold; //0x151C
+ float m_hurt_health_threshold; //0x1520
+ char pad_1524[12]; //0x1524
+ void* m_seat_info; //0x1530
+ char pad_1538[220]; //0x1538
+ uint16_t m_cash; //0x1614
+ char pad_1616[842]; //0x1616
+ uint8_t fired_sticky_bombs; //0x1960 reverse from 1.66 2824 function E8 ? ? ? 48 8B F8 EB 5F add(1).rip(), function string: WM_MAX_STICKY
+ uint8_t fired_unk_0; //0x1961
+ uint8_t fired_flares; //0x1962
+ uint8_t fired_unk_1; //0x1963
+
+ float get_speed() { return sqrt(m_velocity.x * m_velocity.x + m_velocity.y * m_velocity.y + m_velocity.z * m_velocity.z); }
+
+ rage::fvector3 get_bone_coords(ePedBoneType type)
+ {
+ rage::fvector3 world_coords;
+ model_to_world(m_bone_info[(uint32_t)type].model_coords, world_coords);
+ return world_coords;
+ }
+
+ bool can_be_ragdolled() { return m_ped_type & 0x20; }
+
+ uint32_t get_ped_type() { return m_ped_type << 11 >> 25; }
+
+ bool has_seatbelt() { return m_seatbelt & 0x3; }
+
+ void forced_aim(bool toggle) { m_forced_aim ^= (m_forced_aim ^ -(char)toggle) & 0x20; }
+}; //Size: 0x1964
+static_assert(sizeof(CPed) == 0x1964);
+#pragma pack(pop)
diff --git a/classes/src/ped/CPedBoneInfo.hpp b/classes/src/ped/CPedBoneInfo.hpp
new file mode 100644
index 0000000000..ba54b77b69
--- /dev/null
+++ b/classes/src/ped/CPedBoneInfo.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "../rage/vector.hpp"
+
+enum class ePedBoneType
+{
+ HEAD,
+ L_FOOT,
+ R_FOOT,
+ L_ANKLE,
+ R_ANKLE,
+ L_HAND,
+ R_HAND,
+ NECK,
+ ABDOMEN
+};
+
+class CPedBoneInfo
+{
+public:
+ rage::fvector3 model_coords;
+ char pad_000C[4];
+};
+static_assert(sizeof(CPedBoneInfo) == 0x10);
\ No newline at end of file
diff --git a/classes/src/ped/CPedFactory.hpp b/classes/src/ped/CPedFactory.hpp
new file mode 100644
index 0000000000..bb54363847
--- /dev/null
+++ b/classes/src/ped/CPedFactory.hpp
@@ -0,0 +1,23 @@
+#pragma once
+#include "CPed.hpp"
+
+class CPedFactory
+{
+public:
+ enum class PedCreateFlags
+ {
+ IS_NETWORKED = (1 << 0),
+ IS_PLAYER = (1 << 1)
+ };
+
+ virtual ~CPedFactory() = default;
+ virtual CPed* CreatePed(std::uint8_t* flags, std::uint16_t* model_index, rage::fmatrix44* matrix, bool default_component_variation, bool register_network_object, bool give_default_loadout, bool, bool) = 0; // 0x08
+ virtual CPed* CreateClone(std::uint8_t* flags, std::uint16_t* model_index, rage::fmatrix44* matrix, bool default_component_variation, bool, bool register_network_object, bool) = 0; // 0x10
+ virtual CPed* ClonePed(CPed* ped, bool register_network_object, bool link_blends, bool clone_compressed_damage) = 0; // 0x18
+ virtual CPed* ClonePedToTarget(CPed* source, CPed* target, bool clone_compressed_damage) = 0; // 0x20
+ virtual CPed* CreatePlayer(std::uint8_t* flags, std::uint16_t model_index, rage::fmatrix44* matrix, CPlayerInfo* player_info) = 0; // 0x28
+ virtual void DestroyPed(CPed* ped) = 0; // 0x30
+
+ class CPed* m_local_ped; //0x0008
+}; //Size: 0x0010
+static_assert(sizeof(CPedFactory) == 0x10);
diff --git a/classes/src/ped/CPedIntelligence.hpp b/classes/src/ped/CPedIntelligence.hpp
new file mode 100644
index 0000000000..3dd798eac2
--- /dev/null
+++ b/classes/src/ped/CPedIntelligence.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+class CPedIntelligence
+{
+public:
+ char pad_0000[632]; //0x0000
+ float m_oxygen_time; //0x0278
+}; //Size: 0x027C
+static_assert(sizeof(CPedIntelligence) == 0x27C);
\ No newline at end of file
diff --git a/classes/src/ped/CPedInventory.hpp b/classes/src/ped/CPedInventory.hpp
new file mode 100644
index 0000000000..0f546f3277
--- /dev/null
+++ b/classes/src/ped/CPedInventory.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+#include "../base/atRTTI.hpp"
+
+class CPed;
+
+#pragma pack(push, 8)
+class CPedInventory
+{
+public:
+ DEFINE_RAGE_RTTI(CPedInventory);
+
+ uint64_t unk_0008;
+ CPed* m_ped; //0x0010
+ uint64_t unk_0018;
+ uint32_t unk_0020;
+ uint64_t unk_0028;
+ uint64_t unk_0030;
+ uint32_t unk_0038;
+ char pad_003C[4];
+ char unk_0040;
+ char pad_0041[7];
+ uint64_t unk_0048;
+ uint32_t unk_0050;
+ uint64_t unk_0058;
+ uint64_t unk_0060;
+ uint32_t unk_0068;
+ char pad_006C[4];
+ char unk_0070;
+ char pad_0071[7];
+ bool m_infinite_ammo : 1;
+ bool m_infinite_clip : 1;
+ char pad_0079[7];
+ uint64_t unk_0080;
+};
+static_assert(sizeof(CPedInventory) == 0x88);
+#pragma pack(pop)
diff --git a/classes/src/ped/CPedModelInfo.hpp b/classes/src/ped/CPedModelInfo.hpp
new file mode 100644
index 0000000000..b1c7108742
--- /dev/null
+++ b/classes/src/ped/CPedModelInfo.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "../base/CBaseModelInfo.hpp"
+
+#include
+
+class CPedModelInfo : public CBaseModelInfo
+{
+public:
+ char gapB0[48];
+ uint64_t qwordE0;
+ uint32_t dwordE8;
+ char gapEC[4];
+ uint32_t dwordF0;
+ char gapF4[4];
+ uint64_t qwordF8;
+ uint32_t dword100;
+ uint64_t qword108;
+ uint64_t qword110;
+ uint64_t qword118;
+ uint64_t qword120;
+ uint64_t qword128;
+ uint32_t dword130;
+ char gap134[4];
+ uint32_t ped_type;
+ char gap13C[140];
+ uint64_t qword1C8;
+ uint32_t dword1D0;
+ uint64_t qword1D8;
+ uint32_t dword1E0;
+ char gap1E4[52];
+ uint64_t qword218;
+ char gap220[8];
+ uint64_t qword228;
+ uint32_t dword230;
+ char gap234[4];
+ uint32_t dword238;
+ char gap23C[12];
+ uint64_t qword248;
+ uint64_t qword250;
+ uint64_t qword258;
+ uint64_t qword260;
+ uint64_t qword268;
+ uint64_t qword270;
+ uint64_t qword278;
+ char gap280[16];
+};
+static_assert(sizeof(CPedModelInfo) == 0x290);
diff --git a/classes/src/ped/CPedWeaponManager.hpp b/classes/src/ped/CPedWeaponManager.hpp
new file mode 100644
index 0000000000..3e484a1c13
--- /dev/null
+++ b/classes/src/ped/CPedWeaponManager.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "../weapon/CWeaponInfo.hpp"
+
+#include
+
+class CPedWeaponManager
+{
+public:
+ char pad_0000[16]; //0x0000
+ class CPed* m_owner; //0x0010
+ uint32_t m_selected_weapon_hash; //0x0018
+ char pad_001C[4]; //0x001C
+ class CWeaponInfo* m_weapon_info; //0x0020
+ char pad_0028[72]; //0x0028
+ class CWeaponInfo* m_vehicle_weapon_info; //0x0070
+ class CObject* m_weapon_object; //0x0078
+}; //Size: 0x0080
+static_assert(sizeof(CPedWeaponManager) == 0x80);
diff --git a/classes/src/player/CNonPhysicalPlayerData.hpp b/classes/src/player/CNonPhysicalPlayerData.hpp
new file mode 100644
index 0000000000..13cc735598
--- /dev/null
+++ b/classes/src/player/CNonPhysicalPlayerData.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "../rage/vector.hpp"
+
+#include
+
+namespace rage
+{
+ class nonPhysicalPlayerDataBase
+ {
+ public:
+ virtual ~nonPhysicalPlayerDataBase();
+ virtual void read();
+ virtual void write();
+ virtual void calculate_size();
+ virtual void log();
+ }; //Size: 0x0008
+ static_assert(sizeof(nonPhysicalPlayerDataBase) == 0x8);
+}
+
+#pragma pack(push, 4)
+class CNonPhysicalPlayerData : public rage::nonPhysicalPlayerDataBase
+{
+public:
+ int32_t m_bubble_id; //0x0008
+ int32_t m_player_id; //0x000C
+ rage::fvector3 m_position; //0x0010
+}; //Size: 0x001C
+static_assert(sizeof(CNonPhysicalPlayerData) == 0x1C);
+#pragma pack(pop)
diff --git a/classes/src/player/CPlayerAngles.hpp b/classes/src/player/CPlayerAngles.hpp
new file mode 100644
index 0000000000..bdbdb8b40c
--- /dev/null
+++ b/classes/src/player/CPlayerAngles.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "../rage/vector.hpp"
+#include "CPlayerCameraData.hpp"
+
+class CPlayerAngles
+{
+public:
+ char pad_0000[16]; //0x0000
+ CPlayerCameraData* m_cam_data; //0x0010
+ char pad_0018[24]; //0x0018
+ rage::fvector3 m_right; //0x0030
+ char pad_003C[4]; //0x003C
+ rage::fvector3 m_forward; //0x0040
+ char pad_004C[4]; //0x004C
+ rage::fvector3 m_up; //0x0050
+ char pad_005C[4]; //0x005C
+ rage::fvector3 m_position; //0x0060
+ char pad_006C[36]; //0x006C
+}; //Size: 0x0090
+static_assert(sizeof(CPlayerAngles) == 0x90);
diff --git a/classes/src/player/CPlayerCameraData.hpp b/classes/src/player/CPlayerCameraData.hpp
new file mode 100644
index 0000000000..4570ada7c5
--- /dev/null
+++ b/classes/src/player/CPlayerCameraData.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+class CPlayerCameraData
+{
+public:
+ char m_unk_0x0[0x30];
+ float m_fov;
+ char m_unk_0x34[0x24];
+ uint32_t m_zoom_state;
+};
+static_assert(sizeof(CPlayerCameraData) == 0x5C);
diff --git a/classes/src/player/CPlayerInfo.hpp b/classes/src/player/CPlayerInfo.hpp
new file mode 100644
index 0000000000..5b5a0bd393
--- /dev/null
+++ b/classes/src/player/CPlayerInfo.hpp
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "../rage/rlGamerInfo.hpp"
+
+#include
+
+enum class eGameState : int32_t
+{
+ Invalid = -1,
+ Playing,
+ Died,
+ Arrested,
+ FailedMission,
+ LeftGame,
+ Respawn,
+ InMPCutscene
+};
+
+#pragma pack(push, 4)
+class CPlayerInfo
+{
+public:
+ char pad_0000[32]; //0x0000
+ class rage::rlGamerInfo m_net_player_data; //0x0020
+ char pad_0110[184]; //0x0110
+ float m_swim_speed; //0x01C8
+ char pad_01CC[20]; //0x01CC
+ uint32_t m_water_proof; //0x01E0
+ char pad_01E4[76]; //0x01E4
+ eGameState m_game_state; //0x0230
+ char pad_0234[12]; //0x0234
+ class CPed* m_ped; //0x0240
+ char pad_0248[40]; //0x0248
+ uint32_t m_frame_flags; //0x0270
+ char pad_0274[52]; //0x0274
+ uint32_t m_player_controls; //0x02A8
+ char pad_02AC[1248]; //0x02AC
+ float m_wanted_can_change; //0x078C
+ char pad_0790[304]; //0x0790
+ uint32_t m_npc_ignore; //0x08C0
+ char pad_08C4[12]; //0x08C4
+ bool m_is_wanted; //0x08D0
+ char pad_08D1[7]; //0x08D1
+ uint32_t m_wanted_level; //0x08D8
+ uint32_t m_wanted_level_display; //0x08DC
+ char pad_08E0[1120]; //0x08E0
+ float m_run_speed; //0x0D40
+ float m_stamina; //0x0D44
+ float m_stamina_regen; //0x0D48
+ char pad_0D4C[16]; //0x0D4C
+ float m_weapon_damage_mult; //0x0D5C
+ float m_weapon_defence_mult; //0x0D60
+ char pad_0D64[4]; //0x0D64
+ float m_melee_weapon_damage_mult; //0x0D68
+ float m_melee_damage_mult; //0x0D6C
+ float m_melee_defence_mult; //0x0D70
+ char pad_0D74[8]; //0x0D74
+ float m_melee_weapon_defence_mult; //0x0D7C
+}; //Size: 0x0D80
+static_assert(sizeof(CPlayerInfo) == 0xD80);
+#pragma pack(pop)
diff --git a/classes/src/rage/atArray.hpp b/classes/src/rage/atArray.hpp
new file mode 100644
index 0000000000..b0b9ca1e35
--- /dev/null
+++ b/classes/src/rage/atArray.hpp
@@ -0,0 +1,234 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+#include "script/tlsContext.hpp"
+
+namespace rage
+{
+#pragma pack(push, 8)
+ template
+ class atArray
+ {
+ public:
+ atArray() :
+ m_data(nullptr),
+ m_size(0),
+ m_count(0)
+ {
+
+ }
+
+#if _WIN32
+ atArray(const atArray& right)
+ {
+ m_count = right.m_count;
+ m_size = right.m_size;
+
+ if (right.m_data == nullptr)
+ {
+ m_data = nullptr;
+ return;
+ }
+
+ m_data = (T*)tlsContext::get()->m_allocator->Allocate(m_size * sizeof(T), 16, 0);
+ std::uninitialized_copy(right.m_data, right.m_data + right.m_count, m_data);
+ }
+
+ atArray(void* data_ptr, std::uint16_t size, std::uint16_t count) :
+ m_data(data_ptr),
+ m_size(size),
+ m_count(count)
+ {
+
+ }
+
+ void clear()
+ {
+ m_count = 0;
+ m_size = 0;
+
+ if (m_data)
+ {
+ tlsContext::get()->m_allocator->Free(m_data);
+
+ m_data = nullptr;
+ }
+ }
+
+ bool append(atArray value_array)
+ {
+ auto value_array_size = value_array.size();
+ auto old_capacity = m_count;
+
+ if ((value_array_size + m_count) > (std::numeric_limits::max)())
+ return false;
+
+ auto size = (uint16_t)value_array_size;
+ expand(m_count + size);
+ m_size += size;
+
+ auto i = old_capacity;
+ for (auto iter_value : value_array)
+ {
+ m_data[i] = iter_value;
+ i++;
+ }
+ return true;
+ }
+
+ bool append(std::vector value_array)
+ {
+ auto value_array_size = value_array.size();
+ auto old_capacity = m_count;
+
+ if ((value_array_size + m_count) > (std::numeric_limits::max)())
+ return false;
+
+ auto size = (uint16_t)value_array_size;
+ expand(m_count + size);
+ m_size += size;
+
+ auto i = old_capacity;
+ for (auto iter_value : value_array)
+ {
+ m_data[i] = iter_value;
+ i++;
+ }
+ return true;
+ }
+
+ bool append(const std::initializer_list value_array)
+ {
+ auto value_array_size = value_array.size();
+ auto old_capacity = m_count;
+
+ if ((value_array_size + m_count) > (std::numeric_limits::max)())
+ return false;
+
+ 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++;
+ }
+ return true;
+ }
+
+ 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*)tlsContext::get()->m_allocator->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);
+ tlsContext::get()->m_allocator->Free(m_data);
+ }
+
+ m_data = newOffset;
+ m_count = newSize;
+ }
+
+ void append(T value)
+ {
+ set(m_count, value);
+ }
+#endif
+
+ 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];
+ }
+
+ bool contains(T comparator)
+ {
+ for (auto iter_value : *this)
+ {
+ if (iter_value == comparator)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, const atArray& j)
+ {
+ o << "Array Size: " << j.size() << std::endl;
+ for (int i = 0; i < j.size(); i++)
+ {
+ T item = j[i];
+ if (std::is_pointer())
+ o << "\tArray Pointer: " << std::hex << std::uppercase << item << std::nouppercase << std::dec << " Item: [" << std::hex << std::uppercase << (*(T*)item) << std::nouppercase << std::dec << "]";
+ 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) == 0x10, "rage::atArray is not properly sized");
+#pragma pack(pop)
+}
diff --git a/classes/src/rage/atReferenceCounter.hpp b/classes/src/rage/atReferenceCounter.hpp
new file mode 100644
index 0000000000..e9bb2facc2
--- /dev/null
+++ b/classes/src/rage/atReferenceCounter.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "../base/datBase.hpp"
+
+namespace rage
+{
+ class atReferenceCounter : public datBase
+ {
+ public:
+ atReferenceCounter() : m_ref_count(0) {}
+
+ void AddReference() {
+ m_ref_count++;
+ }
+
+ void ReleaseReference() {
+ m_ref_count--;
+ if(m_ref_count == 0) {
+ delete this;
+ }
+ }
+
+ int GetReferenceCount() const {
+ return m_ref_count;
+ }
+
+ private:
+ int m_ref_count; // 0x0000
+ };
+}
\ No newline at end of file
diff --git a/classes/src/rage/atSingleton.hpp b/classes/src/rage/atSingleton.hpp
new file mode 100644
index 0000000000..bd3f8d02b0
--- /dev/null
+++ b/classes/src/rage/atSingleton.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+namespace rage
+{
+ template
+ struct atSingleton
+ {
+ private:
+ T* m_basePtr{};
+
+ public:
+ bool isValid() const
+ {
+ return m_basePtr != nullptr;
+ }
+
+ T* getInstance()
+ {
+ return m_basePtr;
+ }
+ };
+}
diff --git a/classes/src/rage/gameSkeleton.hpp b/classes/src/rage/gameSkeleton.hpp
new file mode 100644
index 0000000000..7e72884776
--- /dev/null
+++ b/classes/src/rage/gameSkeleton.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include
+#include "atArray.hpp"
+
+namespace rage
+{
+
+#pragma pack(push, 8)
+
+struct skeleton_data
+{
+ uint64_t m_init_func; //0x0
+ uint64_t m_shutdown_func; //0x8
+ uint32_t m_unk1; // 0x10
+ uint32_t m_unk2; // 0x14
+ uint32_t m_unk3; // 0x18
+ uint32_t m_unk4; // 0x1C
+ uint32_t m_hash; // 0x20
+};
+static_assert(sizeof(skeleton_data) == 0x28);
+
+struct game_skeleton_update_base
+{
+ virtual ~game_skeleton_update_base() = default;
+ virtual void run() = 0;
+ uint64_t m_pad; // 0x08
+ uint32_t m_hash; // 0x10
+ game_skeleton_update_base* m_next; // 0x18
+};
+static_assert(sizeof(game_skeleton_update_base) == 0x20);
+
+struct game_skeleton_update_group : game_skeleton_update_base
+{
+ game_skeleton_update_base* m_head; // 0x20
+};
+static_assert(sizeof(game_skeleton_update_group) == 0x28);
+
+struct game_skeleton_update_element : game_skeleton_update_base
+{
+ void(*m_function)(); // 0x20
+};
+static_assert(sizeof(game_skeleton_update_element) == 0x28);
+
+struct game_skeleton_update_mode
+{
+ int m_type; // 0x00
+ game_skeleton_update_base* m_head; // 0x08
+ game_skeleton_update_mode* m_next; // 0x10
+};
+static_assert(sizeof(game_skeleton_update_mode) == 0x18);
+
+struct game_skeleton_init_dependency
+{
+ int m_level; // 0x00
+ atArray m_data; // 0x08
+ game_skeleton_init_dependency* m_next; // 0x10
+};
+
+struct game_skeleton_mode
+{
+ int m_type; // 0x00
+ game_skeleton_init_dependency* m_head; // 0x08
+ game_skeleton_mode* m_next; // 0x10
+};
+static_assert(sizeof(game_skeleton_mode) == 0x18);
+
+struct game_skeleton
+{
+ virtual ~game_skeleton() = 0;
+ uint32_t m_unk1; //0x08
+ uint32_t m_unk2; //0x0C
+ uint32_t m_unk3; // 0x10
+ uint32_t m_unk4; // 0x14
+ atArray m_sys_data; // 0x18
+ uint32_t m_unk5; // 0x28
+ void* m_unk6[32]; // 0x30
+ game_skeleton_mode* m_init_modes; // 0x130
+ game_skeleton_mode* m_shutdown_modes; // 0x138
+ game_skeleton_update_mode* m_update_modes; // 0x140
+};
+static_assert(sizeof(game_skeleton) == 0x148);
+
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/rage/joaat.hpp b/classes/src/rage/joaat.hpp
new file mode 100644
index 0000000000..482311473b
--- /dev/null
+++ b/classes/src/rage/joaat.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+#include
+
+namespace rage
+{
+ using joaat_t = std::uint32_t;
+ inline constexpr char joaat_to_lower(char c)
+ {
+ return c >= 'A' && c <= 'Z' ? c | 1 << 5 : c;
+ }
+
+ inline constexpr joaat_t joaat(const std::string_view str)
+ {
+ joaat_t hash = 0;
+ for (auto c : str)
+ {
+ hash += joaat_to_lower(c);
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
+ }
+};
diff --git a/classes/src/rage/rlGamerHandle.hpp b/classes/src/rage/rlGamerHandle.hpp
new file mode 100644
index 0000000000..3feebdd9ae
--- /dev/null
+++ b/classes/src/rage/rlGamerHandle.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+
+namespace rage
+{
+#pragma pack(push,8)
+ class rlGamerHandle
+ {
+ public:
+ uint64_t m_rockstar_id; //0x0000
+ uint8_t m_platform; //0x0008
+ uint8_t unk_0009; //0x0009
+
+ inline rlGamerHandle() = default;
+
+ inline rlGamerHandle(uint64_t rockstar_id) :
+ m_rockstar_id(rockstar_id),
+ m_platform(3),
+ unk_0009(0)
+ {
+ }
+ }; //Size: 0x0010
+ static_assert(sizeof(rlGamerHandle) == 0x10);
+#pragma pack(pop)
+}
\ No newline at end of file
diff --git a/classes/src/rage/rlGamerInfo.hpp b/classes/src/rage/rlGamerInfo.hpp
new file mode 100644
index 0000000000..a061a496db
--- /dev/null
+++ b/classes/src/rage/rlGamerInfo.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+#include "rlGamerInfoBase.hpp"
+
+namespace rage
+{
+#pragma pack(push,8)
+ class rlGamerInfo : public rlGamerInfoBase
+ {
+ public:
+ uint64_t m_host_token;
+
+ union
+ {
+ rlGamerHandle m_gamer_handle_2;
+ uint32_t m_peer_id_2; // not found in all instances
+ };
+
+ uint32_t m_ros_privilege;
+ char m_name[17];
+ }; //Size: 0x0098
+ static_assert(sizeof(rlGamerInfo) == 0xF0);
+#pragma pack(pop)
+}
diff --git a/classes/src/rage/rlGamerInfoBase.hpp b/classes/src/rage/rlGamerInfoBase.hpp
new file mode 100644
index 0000000000..d63a356629
--- /dev/null
+++ b/classes/src/rage/rlGamerInfoBase.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+#include
+#include "rlGamerHandle.hpp"
+#include "network/netPeerAddress.hpp"
+
+namespace rage
+{
+#pragma pack(push,8)
+ class rlGamerInfoBase
+ {
+ public:
+ int m_security_enabled; //0x0000
+ uint64_t m_peer_id; //0x0008
+ rlGamerHandle m_gamer_handle; //0x0010
+ char m_aes_key[0x28]; //0x0020
+ netPeerAddress m_relay_address; //0x0048
+ char m_relay_signature[0x40]; //0x0068
+ netAddress m_external_ip; //0x00A8
+ uint16_t m_external_port; //0x00AC
+ netAddress m_internal_ip; //0x00B0
+ uint16_t m_internal_port; //0x00B4
+ uint32_t m_nat_type; //0x00B8
+ bool m_force_relays; //0x00BC
+ };
+ static_assert(sizeof(rlGamerInfoBase) == 0xC0);
+#pragma pack(pop)
+}
diff --git a/classes/src/rage/rlMetric.hpp b/classes/src/rage/rlMetric.hpp
new file mode 100644
index 0000000000..79dea88f18
--- /dev/null
+++ b/classes/src/rage/rlMetric.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include "joaat.hpp"
+
+namespace rage
+{
+ class rlMetric
+ {
+ public:
+ virtual ~rlMetric() = default;
+
+ virtual int _0x08() { return 0; }; // returns a constant integer
+
+ virtual int _0x10() { return 0; }; // returns a constant integer
+
+ virtual int _0x18() { return 0; };
+
+ virtual const char* get_name() { return ""; };
+
+ virtual bool serialize(void* serializer) { return false; };
+
+ virtual int get_size() { return 0; };
+
+ virtual joaat_t get_name_hash() { return 0; };
+ };
+};
\ No newline at end of file
diff --git a/classes/src/rage/rlQueryPresenceAttributesContext.hpp b/classes/src/rage/rlQueryPresenceAttributesContext.hpp
new file mode 100644
index 0000000000..5f94abebb1
--- /dev/null
+++ b/classes/src/rage/rlQueryPresenceAttributesContext.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+
+namespace rage
+{
+ class rlQueryPresenceAttributesContext
+ {
+ public:
+ char m_presence_attribute_key[64]; //0x0000
+ union
+ {
+ char m_presence_attribute_string_value[256]; //0x0040
+ uint64_t m_presence_attribute_int_value;
+ };
+ uint32_t m_presence_attibute_type; //0x0140
+ char pad_0144[4]; //0x0144
+ }; //Size: 0x0148
+ static_assert(sizeof(rage::rlQueryPresenceAttributesContext) == 0x148);
+}
diff --git a/classes/src/rage/rlScHandle.hpp b/classes/src/rage/rlScHandle.hpp
new file mode 100644
index 0000000000..054b1ad398
--- /dev/null
+++ b/classes/src/rage/rlScHandle.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+
+namespace rage
+{
+#pragma pack(push, 8)
+ class rlScHandle
+ {
+ public:
+ uint64_t m_rockstar_id; //0x0000
+ int16_t unk_0008;
+ uint8_t m_platform; //0x000A
+ char pad[5]{}; //0x000B
+
+ inline rlScHandle() = default;
+
+ inline rlScHandle(uint64_t rockstar_id) :
+ m_rockstar_id(rockstar_id),
+ m_platform(3),
+ unk_0008(0)
+ {
+ }
+ }; //Size: 0x0010
+ static_assert(sizeof(rlScHandle) == 0x10);
+#pragma pack(pop)
+}
diff --git a/classes/src/rage/rlSessionByGamerTaskResult.hpp b/classes/src/rage/rlSessionByGamerTaskResult.hpp
new file mode 100644
index 0000000000..0868e5ad82
--- /dev/null
+++ b/classes/src/rage/rlSessionByGamerTaskResult.hpp
@@ -0,0 +1,13 @@
+#pragma once
+#include "rlGamerHandle.hpp"
+#include "rlSessionInfo.hpp"
+
+namespace rage
+{
+ class rlSessionByGamerTaskResult
+ {
+ public:
+ rlGamerHandle m_gamer_handle{ 0 };
+ rlSessionInfo m_session_info;
+ };
+}
diff --git a/classes/src/rage/rlSessionInfo.hpp b/classes/src/rage/rlSessionInfo.hpp
new file mode 100644
index 0000000000..0e81a06a69
--- /dev/null
+++ b/classes/src/rage/rlSessionInfo.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+#include "../rage/rlGamerInfoBase.hpp"
+
+namespace rage
+{
+ class rlSessionInfo
+ {
+ public:
+ uint64_t m_unk; //0x0000
+ uint64_t m_session_token; //0x0008
+ rlGamerInfoBase m_net_player_data; //0x0010
+ };
+ static_assert(sizeof(rlSessionInfo) == 0xD0);
+}
\ No newline at end of file
diff --git a/classes/src/rage/rlTaskStatus.hpp b/classes/src/rage/rlTaskStatus.hpp
new file mode 100644
index 0000000000..706b37617c
--- /dev/null
+++ b/classes/src/rage/rlTaskStatus.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace rage
+{
+ struct rlTaskStatus
+ {
+ int status = 0;
+ int unk = 0;
+ };
+}
\ No newline at end of file
diff --git a/classes/src/rage/scrValue.hpp b/classes/src/rage/scrValue.hpp
new file mode 100644
index 0000000000..291f6668f6
--- /dev/null
+++ b/classes/src/rage/scrValue.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#include
+using LPCSTR = const char*; //For Linux support, but I didn't want to make the class inaccurate
+
+namespace rage
+{
+ union scrValue
+ {
+ int Int;
+ unsigned int Uns;
+ float Float;
+ LPCSTR String;
+ scrValue* Reference;
+ uint64_t Any;
+ bool operator==(const scrValue& val) {
+ return Int == val.Int;
+ }
+ };
+}
diff --git a/classes/src/rage/sysMemAllocator.hpp b/classes/src/rage/sysMemAllocator.hpp
new file mode 100644
index 0000000000..54e8ea7f29
--- /dev/null
+++ b/classes/src/rage/sysMemAllocator.hpp
@@ -0,0 +1,25 @@
+#pragma once
+#include
+#include "base/atRTTI.hpp"
+
+namespace rage
+{
+ class sysMemAllocator
+ {
+ public:
+ DEFINE_RAGE_RTTI(rage::sysMemAllocator);
+ virtual void SetQuitOnFail(bool) = 0;
+ virtual void* Allocate(std::size_t size, std::size_t align, int subAllocator) = 0;
+ virtual void* TryAllocate(std::size_t size, std::size_t align, int subAllocator) = 0;
+ virtual void Free(void* pointer) = 0;
+ virtual void TryFree(void* pointer) = 0;
+ virtual void Resize(void* pointer, std::size_t size) = 0;
+ virtual sysMemAllocator* GetAllocator(int allocator) const = 0;
+ virtual sysMemAllocator* GetAllocator(int allocator) = 0;
+ virtual sysMemAllocator* GetPointerOwner(void* pointer) = 0;
+ virtual std::size_t GetSize(void* pointer) const = 0;
+ virtual std::size_t GetMemoryUsed(int memoryBucket) = 0;
+ virtual std::size_t GetMemoryAvailable() = 0;
+
+ };
+}
\ No newline at end of file
diff --git a/classes/src/rage/vector.hpp b/classes/src/rage/vector.hpp
new file mode 100644
index 0000000000..c83f9e5947
--- /dev/null
+++ b/classes/src/rage/vector.hpp
@@ -0,0 +1,87 @@
+#pragma once
+
+namespace rage
+{
+ template
+ union vector2
+ {
+ T data[2];
+ struct { T x, y; };
+
+ vector2(T x, T y) :
+ x(x),
+ y(y)
+ {
+ }
+
+ vector2() :
+ x(),
+ y()
+ {
+ }
+ };
+
+ template
+ union vector3
+ {
+ T data[3];
+ struct { T x, y, z; };
+
+ vector3(T x, T y, T z) :
+ x(x),
+ y(y),
+ z(z)
+ {
+ }
+
+ vector3() :
+ x(),
+ y(),
+ z()
+ {
+ }
+ };
+
+ template
+ union vector4
+ {
+ T data[4];
+ struct { T x, y, z, w; };
+
+ vector4(T x, T y, T z, T w) :
+ x(x),
+ y(y),
+ z(z),
+ w(w)
+ {
+ }
+
+ vector4() :
+ x(),
+ y(),
+ z(),
+ w()
+ {
+ }
+ };
+
+ template
+ union matrix34
+ {
+ T data[3][4];
+ struct { struct { T x, y, z, w; } rows[3]; };
+ };
+
+ template
+ union matrix44
+ {
+ T data[4][4];
+ struct { struct { T x, y, z, w; } rows[4]; };
+ };
+
+ typedef vector2 fvector2;
+ typedef vector3 fvector3;
+ typedef vector4 fvector4;
+ typedef matrix34 fmatrix34;
+ typedef matrix44 fmatrix44;
+}
diff --git a/classes/src/script/CGameScriptObjInfo.hpp b/classes/src/script/CGameScriptObjInfo.hpp
new file mode 100644
index 0000000000..b2b50743a7
--- /dev/null
+++ b/classes/src/script/CGameScriptObjInfo.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#include "scriptId.hpp"
+#include "types.hpp"
+
+#pragma pack(push, 4)
+class CGameScriptObjInfo
+{
+public:
+ virtual ~CGameScriptObjInfo() = default;
+
+ ScrHandle m_local_handle; // 0x8
+ uint16_t m_network_handle; // 0xC
+ CGameScriptId m_script_id; // 0x10
+};
+static_assert(sizeof(CGameScriptObjInfo) == 0x50);
+#pragma pack(pop)
\ No newline at end of file
diff --git a/classes/src/script/GtaThread.hpp b/classes/src/script/GtaThread.hpp
new file mode 100644
index 0000000000..da2a9e6d4e
--- /dev/null
+++ b/classes/src/script/GtaThread.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#include "scrThread.hpp"
+
+class GtaThread : public rage::scrThread
+{
+public:
+ rage::joaat_t m_script_hash; // 0x128
+ int m_force_cleanup_ip; // 0x12C
+ int m_force_cleanup_fp; // 0x130
+ int m_force_cleanup_sp; // 0x134
+ int m_force_cleanup_filter; // 0x138
+ int m_force_cleanup_cause; // 0x13C
+ std::int32_t m_instance_id; // 0x140
+ char m_padding4[0x04]; // 0x144
+ std::uint8_t m_flag1; // 0x148
+ bool m_safe_for_network_game; // 0x149
+ char m_padding5[0x02]; // 0x14A
+ bool m_is_minigame_script; // 0x14C
+ char m_padding6[0x02]; // 0x14D
+ bool m_can_be_paused; // 0x14F
+ bool m_can_remove_blips_from_other_scripts; // 0x150
+ char m_padding7[0x2]; // 0x151
+ std::uint8_t m_force_cleanup_state; // 0x153
+ char m_padding8[0xC]; // 0x154
+};
+static_assert(sizeof(GtaThread) == 0x160);
\ No newline at end of file
diff --git a/classes/src/script/HudColor.hpp b/classes/src/script/HudColor.hpp
new file mode 100644
index 0000000000..b0852ca0cf
--- /dev/null
+++ b/classes/src/script/HudColor.hpp
@@ -0,0 +1,222 @@
+#pragma once
+#include "types.hpp"
+
+enum class HudColor : std::uint32_t
+{
+ HUD_COLOUR_PURE_WHITE,
+ HUD_COLOUR_WHITE,
+ HUD_COLOUR_BLACK,
+ HUD_COLOUR_GREY,
+ HUD_COLOUR_GREYLIGHT,
+ HUD_COLOUR_GREYDARK,
+ HUD_COLOUR_RED,
+ HUD_COLOUR_REDLIGHT,
+ HUD_COLOUR_REDDARK,
+ HUD_COLOUR_BLUE,
+ HUD_COLOUR_BLUELIGHT,
+ HUD_COLOUR_BLUEDARK,
+ HUD_COLOUR_YELLOW,
+ HUD_COLOUR_YELLOWLIGHT,
+ HUD_COLOUR_YELLOWDARK,
+ HUD_COLOUR_ORANGE,
+ HUD_COLOUR_ORANGELIGHT,
+ HUD_COLOUR_ORANGEDARK,
+ HUD_COLOUR_GREEN,
+ HUD_COLOUR_GREENLIGHT,
+ HUD_COLOUR_GREENDARK,
+ HUD_COLOUR_PURPLE,
+ HUD_COLOUR_PURPLELIGHT,
+ HUD_COLOUR_PURPLEDARK,
+ HUD_COLOUR_PINK,
+ HUD_COLOUR_RADAR_HEALTH,
+ HUD_COLOUR_RADAR_ARMOUR,
+ HUD_COLOUR_RADAR_DAMAGE,
+ HUD_COLOUR_NET_PLAYER1,
+ HUD_COLOUR_NET_PLAYER2,
+ HUD_COLOUR_NET_PLAYER3,
+ HUD_COLOUR_NET_PLAYER4,
+ HUD_COLOUR_NET_PLAYER5,
+ HUD_COLOUR_NET_PLAYER6,
+ HUD_COLOUR_NET_PLAYER7,
+ HUD_COLOUR_NET_PLAYER8,
+ HUD_COLOUR_NET_PLAYER9,
+ HUD_COLOUR_NET_PLAYER10,
+ HUD_COLOUR_NET_PLAYER11,
+ HUD_COLOUR_NET_PLAYER12,
+ HUD_COLOUR_NET_PLAYER13,
+ HUD_COLOUR_NET_PLAYER14,
+ HUD_COLOUR_NET_PLAYER15,
+ HUD_COLOUR_NET_PLAYER16,
+ HUD_COLOUR_NET_PLAYER17,
+ HUD_COLOUR_NET_PLAYER18,
+ HUD_COLOUR_NET_PLAYER19,
+ HUD_COLOUR_NET_PLAYER20,
+ HUD_COLOUR_NET_PLAYER21,
+ HUD_COLOUR_NET_PLAYER22,
+ HUD_COLOUR_NET_PLAYER23,
+ HUD_COLOUR_NET_PLAYER24,
+ HUD_COLOUR_NET_PLAYER25,
+ HUD_COLOUR_NET_PLAYER26,
+ HUD_COLOUR_NET_PLAYER27,
+ HUD_COLOUR_NET_PLAYER28,
+ HUD_COLOUR_NET_PLAYER29,
+ HUD_COLOUR_NET_PLAYER30,
+ HUD_COLOUR_NET_PLAYER31,
+ HUD_COLOUR_NET_PLAYER32,
+ HUD_COLOUR_SIMPLEBLIP_DEFAULT,
+ HUD_COLOUR_MENU_BLUE,
+ HUD_COLOUR_MENU_GREY_LIGHT,
+ HUD_COLOUR_MENU_BLUE_EXTRA_DARK,
+ HUD_COLOUR_MENU_YELLOW,
+ HUD_COLOUR_MENU_YELLOW_DARK,
+ HUD_COLOUR_MENU_GREEN,
+ HUD_COLOUR_MENU_GREY,
+ HUD_COLOUR_MENU_GREY_DARK,
+ HUD_COLOUR_MENU_HIGHLIGHT,
+ HUD_COLOUR_MENU_STANDARD,
+ HUD_COLOUR_MENU_DIMMED,
+ HUD_COLOUR_MENU_EXTRA_DIMMED,
+ HUD_COLOUR_BRIEF_TITLE,
+ HUD_COLOUR_MID_GREY_MP,
+ HUD_COLOUR_NET_PLAYER1_DARK,
+ HUD_COLOUR_NET_PLAYER2_DARK,
+ HUD_COLOUR_NET_PLAYER3_DARK,
+ HUD_COLOUR_NET_PLAYER4_DARK,
+ HUD_COLOUR_NET_PLAYER5_DARK,
+ HUD_COLOUR_NET_PLAYER6_DARK,
+ HUD_COLOUR_NET_PLAYER7_DARK,
+ HUD_COLOUR_NET_PLAYER8_DARK,
+ HUD_COLOUR_NET_PLAYER9_DARK,
+ HUD_COLOUR_NET_PLAYER10_DARK,
+ HUD_COLOUR_NET_PLAYER11_DARK,
+ HUD_COLOUR_NET_PLAYER12_DARK,
+ HUD_COLOUR_NET_PLAYER13_DARK,
+ HUD_COLOUR_NET_PLAYER14_DARK,
+ HUD_COLOUR_NET_PLAYER15_DARK,
+ HUD_COLOUR_NET_PLAYER16_DARK,
+ HUD_COLOUR_NET_PLAYER17_DARK,
+ HUD_COLOUR_NET_PLAYER18_DARK,
+ HUD_COLOUR_NET_PLAYER19_DARK,
+ HUD_COLOUR_NET_PLAYER20_DARK,
+ HUD_COLOUR_NET_PLAYER21_DARK,
+ HUD_COLOUR_NET_PLAYER22_DARK,
+ HUD_COLOUR_NET_PLAYER23_DARK,
+ HUD_COLOUR_NET_PLAYER24_DARK,
+ HUD_COLOUR_NET_PLAYER25_DARK,
+ HUD_COLOUR_NET_PLAYER26_DARK,
+ HUD_COLOUR_NET_PLAYER27_DARK,
+ HUD_COLOUR_NET_PLAYER28_DARK,
+ HUD_COLOUR_NET_PLAYER29_DARK,
+ HUD_COLOUR_NET_PLAYER30_DARK,
+ HUD_COLOUR_NET_PLAYER31_DARK,
+ HUD_COLOUR_NET_PLAYER32_DARK,
+ HUD_COLOUR_BRONZE,
+ HUD_COLOUR_SILVER,
+ HUD_COLOUR_GOLD,
+ HUD_COLOUR_PLATINUM,
+ HUD_COLOUR_GANG1,
+ HUD_COLOUR_GANG2,
+ HUD_COLOUR_GANG3,
+ HUD_COLOUR_GANG4,
+ HUD_COLOUR_SAME_CREW,
+ HUD_COLOUR_FREEMODE,
+ HUD_COLOUR_PAUSE_BG,
+ HUD_COLOUR_FRIENDLY,
+ HUD_COLOUR_ENEMY,
+ HUD_COLOUR_LOCATION,
+ HUD_COLOUR_PICKUP,
+ HUD_COLOUR_PAUSE_SINGLEPLAYER,
+ HUD_COLOUR_FREEMODE_DARK,
+ HUD_COLOUR_INACTIVE_MISSION,
+ HUD_COLOUR_DAMAGE,
+ HUD_COLOUR_PINKLIGHT,
+ HUD_COLOUR_PM_MITEM_HIGHLIGHT,
+ HUD_COLOUR_SCRIPT_VARIABLE,
+ HUD_COLOUR_YOGA,
+ HUD_COLOUR_TENNIS,
+ HUD_COLOUR_GOLF,
+ HUD_COLOUR_SHOOTING_RANGE,
+ HUD_COLOUR_FLIGHT_SCHOOL,
+ HUD_COLOUR_NORTH_BLUE,
+ HUD_COLOUR_SOCIAL_CLUB,
+ HUD_COLOUR_PLATFORM_BLUE,
+ HUD_COLOUR_PLATFORM_GREEN,
+ HUD_COLOUR_PLATFORM_GREY,
+ HUD_COLOUR_FACEBOOK_BLUE,
+ HUD_COLOUR_INGAME_BG,
+ HUD_COLOUR_DARTS,
+ HUD_COLOUR_WAYPOINT,
+ HUD_COLOUR_MICHAEL,
+ HUD_COLOUR_FRANKLIN,
+ HUD_COLOUR_TREVOR,
+ HUD_COLOUR_GOLF_P1,
+ HUD_COLOUR_GOLF_P2,
+ HUD_COLOUR_GOLF_P3,
+ HUD_COLOUR_GOLF_P4,
+ HUD_COLOUR_WAYPOINTLIGHT,
+ HUD_COLOUR_WAYPOINTDARK,
+ HUD_COLOUR_PANEL_LIGHT,
+ HUD_COLOUR_MICHAEL_DARK,
+ HUD_COLOUR_FRANKLIN_DARK,
+ HUD_COLOUR_TREVOR_DARK,
+ HUD_COLOUR_OBJECTIVE_ROUTE,
+ HUD_COLOUR_PAUSEMAP_TINT,
+ HUD_COLOUR_PAUSE_DESELECT,
+ HUD_COLOUR_PM_WEAPONS_PURCHASABLE,
+ HUD_COLOUR_PM_WEAPONS_LOCKED,
+ HUD_COLOUR_END_SCREEN_BG,
+ HUD_COLOUR_CHOP,
+ HUD_COLOUR_PAUSEMAP_TINT_HALF,
+ HUD_COLOUR_NORTH_BLUE_OFFICIAL,
+ HUD_COLOUR_SCRIPT_VARIABLE_2,
+ HUD_COLOUR_H,
+ HUD_COLOUR_HDARK,
+ HUD_COLOUR_T,
+ HUD_COLOUR_TDARK,
+ HUD_COLOUR_HSHARD,
+ HUD_COLOUR_CONTROLLER_MICHAEL,
+ HUD_COLOUR_CONTROLLER_FRANKLIN,
+ HUD_COLOUR_CONTROLLER_TREVOR,
+ HUD_COLOUR_CONTROLLER_CHOP,
+ HUD_COLOUR_VIDEO_EDITOR_VIDEO,
+ HUD_COLOUR_VIDEO_EDITOR_AUDIO,
+ HUD_COLOUR_VIDEO_EDITOR_TEXT,
+ HUD_COLOUR_HB_BLUE,
+ HUD_COLOUR_HB_YELLOW,
+ HUD_COLOUR_VIDEO_EDITOR_SCORE,
+ HUD_COLOUR_VIDEO_EDITOR_AUDIO_FADEOUT,
+ HUD_COLOUR_VIDEO_EDITOR_TEXT_FADEOUT,
+ HUD_COLOUR_VIDEO_EDITOR_SCORE_FADEOUT,
+ HUD_COLOUR_HEIST_BACKGROUND,
+ HUD_COLOUR_VIDEO_EDITOR_AMBIENT,
+ HUD_COLOUR_VIDEO_EDITOR_AMBIENT_FADEOUT,
+ HUD_COLOUR_GB,
+ HUD_COLOUR_G,
+ HUD_COLOUR_B,
+ HUD_COLOUR_LOW_FLOW,
+ HUD_COLOUR_LOW_FLOW_DARK,
+ HUD_COLOUR_G1,
+ HUD_COLOUR_G2,
+ HUD_COLOUR_G3,
+ HUD_COLOUR_G4,
+ HUD_COLOUR_G5,
+ HUD_COLOUR_G6,
+ HUD_COLOUR_G7,
+ HUD_COLOUR_G8,
+ HUD_COLOUR_G9,
+ HUD_COLOUR_G10,
+ HUD_COLOUR_G11,
+ HUD_COLOUR_G12,
+ HUD_COLOUR_G13,
+ HUD_COLOUR_G14,
+ HUD_COLOUR_G15,
+ HUD_COLOUR_ADVERSARY,
+ HUD_COLOUR_DEGEN_RED,
+ HUD_COLOUR_DEGEN_YELLOW,
+ HUD_COLOUR_DEGEN_GREEN,
+ HUD_COLOUR_DEGEN_CYAN,
+ HUD_COLOUR_DEGEN_BLUE,
+ HUD_COLOUR_DEGEN_MAGENTA,
+ HUD_COLOUR_STUNT_1,
+ HUD_COLOUR_STUNT_2
+};
\ No newline at end of file
diff --git a/classes/src/script/MPScriptData.hpp b/classes/src/script/MPScriptData.hpp
new file mode 100644
index 0000000000..c9d22fb66e
--- /dev/null
+++ b/classes/src/script/MPScriptData.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include "types.hpp"
+
+struct MP_SCRIPT_DATA
+{
+ SCR_INT Index; // this is an enum
+ uint64_t Args[15];
+ SCR_INT InstanceId;
+ uint64_t MoreArgs[4];
+};
+static_assert(sizeof(MP_SCRIPT_DATA) == 21 * 8);
\ No newline at end of file
diff --git a/classes/src/script/Timer.hpp b/classes/src/script/Timer.hpp
new file mode 100644
index 0000000000..0f21f11ad4
--- /dev/null
+++ b/classes/src/script/Timer.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include "types.hpp"
+
+// this is named stopwatch in the decompiler but "timer" is probably a better name for it
+struct TIMER
+{
+ SCR_INT Time;
+ SCR_BOOL IsInitialized;
+};
+static_assert(sizeof(TIMER) == 2 * 8);
\ No newline at end of file
diff --git a/classes/src/script/dataList.hpp b/classes/src/script/dataList.hpp
new file mode 100644
index 0000000000..bf6682cb75
--- /dev/null
+++ b/classes/src/script/dataList.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#include "../base/datBase.hpp"
+
+namespace rage
+{
+ template
+ class atDNode : public Base
+ {
+ public:
+ T m_data;
+ void *m_unk;
+ atDNode *m_next;
+ };
+
+ template
+ class atDList
+ {
+ public:
+ Node *m_head;
+ Node *m_tail;
+ };
+}
\ No newline at end of file
diff --git a/classes/src/script/globals/GPBD_FM.hpp b/classes/src/script/globals/GPBD_FM.hpp
new file mode 100644
index 0000000000..2f06877056
--- /dev/null
+++ b/classes/src/script/globals/GPBD_FM.hpp
@@ -0,0 +1,659 @@
+#pragma once
+#include "../types.hpp"
+#include "../Timer.hpp"
+#include "../MPScriptData.hpp"
+
+enum class eMissionDataFlags
+{
+ kMissionLaunched = 0,
+ kJobDownloaded = 2,
+ kStartingJob = 3,
+ kRequestingScript = 4,
+ kLaunchedScript = 6, // should be set if kMissionLaunched is set
+ kAutoStartOnProximity = 7, // used by gang attack
+ kNJVSQuickMatch = 8,
+ kVoteLiked = 10,
+ kVoteDisliked = 11,
+ kNoVote = 25
+}; // TODO
+
+enum class eTutorialBitset
+{
+ kInTutorialRace = 0,
+ kTutorialRaceActive = 2,
+ kShowCredits = 4,
+ kNeedFreeVehicle = 6
+};
+
+enum class eGangCallServices
+{
+ kMugger = 0,
+ kMercenary = 1
+};
+
+enum class eVehicleSelectionState
+{
+ NONE,
+ SELECTING,
+ SELECTED
+};
+
+enum class eStatState
+{
+ NONE,
+ LETHARGIC,
+ OUT_OF_SHAPE,
+ HEALTHY,
+ ATHLETE,
+ TRI_ATHLETE,
+ UNTRAINED,
+ SPRAY_AND_PRAY,
+ POLICE_TRAINING,
+ MILITARY_TRAINING,
+ DEAD_EYE,
+ FRAGILE,
+ WEAK,
+ AVERAGE,
+ TOUGH,
+ BODYBUILDER,
+ CLUMSY,
+ LOUD,
+ SNEAKY,
+ HUNTER,
+ NINJA,
+ DANGEROUS,
+ RC_PILOT,
+ COMMERCIAL_PILOT,
+ FIGHTER_PILOT,
+ ACE,
+ UNLICENSED,
+ SUNDAY_DRIVER,
+ COMMUTER,
+ STREET_RACER,
+ PRO_RACER,
+ NORMAL,
+ UNSTABLE,
+ DERANGED,
+ MANIAC,
+ PSYCHOPATH,
+ DRUNK
+};
+
+enum class ePropertyInteriorFlags
+{
+ kOwnerOfInterior = 0,
+ kVisitorOfInterior = 1, // mutually exclusive with above flag
+ kConcealWhenDead = 12,
+ kRenovatingProperty = 19,
+ kPreviewingDecor = 20,
+ kRenovatingClubhouse = 21,
+ kUsingYachtRmBath1 = 22,
+ kUsingYachtRmBath3 = 23,
+ kUsingYachtRmWeeBathroom = 25,
+ kGunLockerOpen = 27,
+ kOfficeSafeOpen = 28,
+ kOfficeAssistantMale = 29
+};
+
+enum class eInteriorStyleFlags
+{
+ kGunLockerShowPumpShotgun = 0,
+ kGunLockerShowMicroSMG = 1,
+ kGunLockerShowC4 = 2, // proximity or sticky
+ kGunLockerShowGrenade = 3,
+ kGunLockerShowCombatMG = 4,
+ kGunLockerShowMarksmanRifle = 5,
+ kPurchasedSnacks = 6,
+ kPurchasedInteriorRenovations = 7,
+ kForceOfficeAssistantSpawn = 8,
+ kAssistantAnimationOver = 9,
+ kChangeInteriorDecorOfficeHelpShown = 11,
+ kChangeInteriorDecorApartmentHelpShown = 12,
+ kOwnsOfficeBedroom = 13,
+ kOwnsClubhouseBikeShop = 16,
+ kOwnsOfficeGunLocker = 17,
+ KOwnsClubhouseWalls = 18, // ???
+ kOwnsClubhouseFurnishings = 19,
+ kOwnsClubhouseDecors = 20
+};
+
+enum class eBusinessHubProductIndex
+{
+ CARGO,
+ WEAPONS,
+ COCAINE,
+ METH,
+ WEED,
+ FORGED_DOCUMENTS,
+ COUNTERFEIT_CASH
+};
+
+struct PLAYLIST_DATA
+{
+ PLAYER_INDEX Host;
+ SCR_INT Flags;
+ SCR_BOOL PAD_0002;
+ SCR_INT CurrentMission;
+ SCR_INT TotalMissions;
+ PLAYER_INDEX PAD_0006;
+};
+static_assert(sizeof(PLAYLIST_DATA) == 6 * 8);
+
+// local copy can be found at Global_2680247
+struct JOB_SETTINGS
+{
+ SCR_ARRAY Settings; // indices vary based on job type. take a look at func_8988 in fmmc_launcher if you wish to change them
+ SCR_INT NumPlayers; // verify
+ SCR_INT PAD_0033;
+ SCR_INT SpawnSimpleInteriorIndex;
+ SCR_INT PAD_0035; // unused
+ SCR_BOOL MatchmakingOpen;
+ SCR_INT ContentHash;
+};
+static_assert(sizeof(JOB_SETTINGS) == 38 * 8);
+
+struct VEHICLE_SELECTION
+{
+ SCR_BOOL Active;
+ SCR_BOOL Active2;
+ PLAYER_INDEX PAD_0002; // set to host by fmmc but not read at all
+ SCR_HASH VehicleModel;
+ SCR_INT CreatorIndex;
+ alignas(8) eVehicleSelectionState State;
+ SCR_INT PrimaryColor;
+ Color3 CustomPrimaryColor;
+ Color3 CustomSecondaryColor;
+ PLAYER_INDEX Partner; // for rally races?
+ GAMER_HANDLE PartnerHandle;
+ SCR_INT PreferredRole; // target assault races
+ SCR_INT PAD_0028; // TODO
+ SCR_INT ControlType; // 1 = kb&m 2 = controller
+ SCR_INT BettingFlags;
+ SCR_INT Team;
+ SCR_INT Flags;
+ SCR_INT JoinedMembers; // bitset of joined transition members set by the host
+ SCR_INT AdversaryOutfitIndex;
+ alignas(8) eStatState StatState; // see func_9142 in fmmc_launcher, shown to other players
+ SCR_INT CashWager; // shown to other players...
+ uint64_t PAD_0037[2]; // TODO
+ SCR_INT PAD_0039; // TODO random integer between 1 and 11
+};
+static_assert(sizeof(VEHICLE_SELECTION) == 40 * 8);
+
+struct STRIKE_TEAM
+{
+ PLAYER_INDEX Target;
+ TIMER Cooldown;
+ SCR_BOOL CancelStrikeTeam; // read but not written to
+ SCR_INT Level;
+};
+static_assert(sizeof(STRIKE_TEAM) == 5 * 8);
+
+struct PLAYER_STATS
+{
+ SCR_INT Team;
+ SCR_INT RP;
+ SCR_INT CrewRP;
+ SCR_INT WalletBalance;
+ SCR_INT HeistBonus;
+ SCR_INT GlobalRP;
+ SCR_INT Rank;
+ TEXT_LABEL_31 CrewTitle;
+ SCR_INT TotalRacesWon;
+ SCR_INT TotalRacesLost;
+ SCR_INT TimesFinishRaceAsTop3;
+ SCR_INT TimesFinishRaceLast;
+ SCR_INT TimesRaceBestLap;
+ SCR_INT TotalDeathmatchesWon;
+ SCR_INT TotalDeathmatchesLost;
+ SCR_INT TotalTeamDeathmatchesWon;
+ SCR_INT TotalTeamDeathmatchesLost;
+ SCR_INT Shots;
+ SCR_INT Hits;
+ SCR_FLOAT KdRatio;
+ SCR_FLOAT DropoutRate;
+ SCR_INT KillsOnPlayers;
+ SCR_INT DeathsByPlayers;
+ SCR_INT TotalFinishDeathmatchAsTop3;
+ SCR_INT TotalFinishDeathmatchLast;
+ SCR_INT DartsTotalWins;
+ SCR_INT DartsTotalMatches;
+ SCR_INT ArmwrestlingTotalWins;
+ SCR_INT ArmwrestlingTotalMatches;
+ SCR_INT TennisMatchesWon;
+ SCR_INT TennisMatchesLost;
+ SCR_INT BaseJumpWins;
+ SCR_INT BaseJumpLosses;
+ SCR_INT GolfWins;
+ SCR_INT GolfLosses;
+ SCR_INT ShootingRangeWins;
+ SCR_INT ShootingRangeLosses;
+ SCR_INT ShootingAbility;
+ SCR_INT MissionWins;
+ SCR_INT TotalMissionsPlayed;
+ SCR_INT SurvivalWins;
+ SCR_INT TotalSurvivalsPlayed;
+ SCR_INT PAD_0049; // TODO
+ SCR_INT MissionsCreated;
+ SCR_INT CommunicationRestrictions;
+ SCR_BOOL CanSpectate;
+ SCR_INT MostFavoriteStation;
+ SCR_INT ProstitutesFrequented;
+ SCR_INT LapDancesBought;
+ SCR_INT Money;
+ SCR_FLOAT WeaponAccuracy;
+ SCR_HASH FavoriteVehicle;
+ SCR_HASH FavoriteWeapon;
+};
+static_assert(sizeof(PLAYER_STATS) == 60 * 8);
+
+struct EXEC_WAREHOUSE_INFO
+{
+ SCR_INT Index;
+ SCR_INT Stock;
+ SCR_INT PAD_0002; // unused
+};
+static_assert(sizeof(EXEC_WAREHOUSE_INFO) == 3 * 8);
+
+struct IE_WAREHOUSE_DATA
+{
+ SCR_INT Index;
+ SCR_INT NumVehicles;
+ SCR_ARRAY Vehicles;
+ SCR_INT PAD_0043; // set to zero and not read
+ SCR_INT OwnedWarehouseVariation;
+};
+static_assert(sizeof(IE_WAREHOUSE_DATA) == 45 * 8);
+
+struct FACTORY_INFO
+{
+ SCR_INT Index;
+ SCR_INT TotalProduct;
+ SCR_INT TotalSupplies;
+ SCR_INT TotalSupplies2; // TODO: what's the difference?
+ uint64_t PAD_0004;
+ SCR_INT EquipmentUpgrades;
+ SCR_BOOL Running;
+ SCR_BOOL SetupDone;
+ SCR_BOOL PAD_0008;
+ SCR_INT Research; // valid only for factory index 5 (bunker)
+ SCR_INT StaffState;
+ SCR_INT ProductValue; // untested
+ SCR_INT StaffAssignmentType; // valid only for factory index 5 (bunker) 0 = manufacturing, 1 = research, 2 = both
+};
+static_assert(sizeof(FACTORY_INFO) == 13 * 8);
+
+struct HANGAR_DATA
+{
+ SCR_INT Index;
+ SCR_INT AppearanceBitset;
+ SCR_INT PAD_0002; // unused
+ SCR_INT TotalContraband;
+ SCR_INT PAD_0004; // unused, a function tries to set it to something but is never called with the right parameters. it isn't read either
+ SCR_BOOL SetupDone;
+};
+static_assert(sizeof(HANGAR_DATA) == 6 * 8);
+
+// facility
+struct DEFUNCT_BASE_DATA
+{
+ SCR_INT Index;
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_INT ObtainedAwards;
+ SCR_INT PAD_0004; // unused, a function tries to set it to something but is never called with the right parameters. it isn't read either
+ SCR_INT PAD_0005;
+ SCR_INT TotalContraband; // wat
+};
+static_assert(sizeof(DEFUNCT_BASE_DATA) == 7 * 8);
+
+// nightclub
+struct BUSINESS_HUB_DATA
+{
+ SCR_INT Index;
+ SCR_INT TotalContraband; // not read by the scripts
+ SCR_INT ProducingBusinesses; // bitset
+ SCR_INT ProducingFactories; // bitset
+ SCR_INT Upgrades;
+ SCR_INT PAD_0005;
+ SCR_INT PAD_0006; // not read by the scripts
+ SCR_INT SetupBitset; // includes owned DJs
+ SCR_ARRAY ProductStocks; // see eBusinessHubProductIndex
+ SCR_ARRAY PAD_0017; // have no clue what this is
+ SCR_ARRAY TotalSoldProduct;
+};
+static_assert(sizeof(BUSINESS_HUB_DATA) == 43 * 8);
+
+// also the nightclub? strange
+struct NIGHTCLUB_DATA
+{
+ SCR_INT Index; // same as BusinessHubData::Index
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_INT AccessSettings; // TODO: figure out how this works
+ SCR_FLOAT Popularity; // 0.0 to 1.0
+ SCR_INT SafeCashValue;
+ SCR_INT EntryCost; // can be set to any arbitrary value
+ SCR_INT CroudVariation;
+ SCR_INT DanceAwardProgress; // "Gold Dancer trophy unlocked."
+ SCR_INT DanceAward2Progress; // "Gold Battler trophy unlocked."
+ TIMER DJMusicChangeTimer;
+};
+static_assert(sizeof(NIGHTCLUB_DATA) == 12 * 8);
+
+struct ARENA_GARAGE_DATA
+{
+ SCR_INT Index; // always one for obvious reasons
+ SCR_INT OwnedGarageFloorLevel;
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_INT InteriorTypeA;
+ SCR_INT InteriorTypeB;
+ SCR_INT SpectatingIndex;
+ SCR_INT SpectatingType;
+ SCR_INT PAD_0008; // unused
+};
+static_assert(sizeof(ARENA_GARAGE_DATA) == 9 * 8);
+
+struct INSIDE_TRACK
+{
+ TEXT_LABEL_63 PlayerName; // real name leak when playing inside track
+ SCR_INT BetHorseID;
+ SCR_INT BetChips;
+};
+static_assert(sizeof(INSIDE_TRACK) == 18 * 8);
+
+// casino penthouse
+struct CASINO_APARTMENT_DATA
+{
+ SCR_INT Index; // always one for obvious reasons
+ SCR_INT PAD_0001; // unused
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ uint64_t PAD_0005[2];
+ INSIDE_TRACK InsideTrack;
+};
+static_assert(sizeof(CASINO_APARTMENT_DATA) == 24 * 8);
+
+struct ARCADE_DATA
+{
+ SCR_INT Index;
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_INT AppearanceBitset3;
+ SCR_INT SafeCashValue;
+ SCR_INT PAD_0005; // unused
+};
+static_assert(sizeof(ARCADE_DATA) == 6 * 8);
+
+struct ARCADE_MACHINES
+{
+ SCR_INT OrderedMachinesBitset;
+ SCR_INT ArrivedMachinesBitset;
+};
+static_assert(sizeof(ARCADE_MACHINES) == 2 * 8);
+
+struct SUBMARINE_DATA
+{
+ SCR_INT AppearanceBitset;
+ SCR_HASH Model; // not read by the scripts, always set to HASH("kosatka")
+ SCR_INT Color; // "PACKED_MP_INT_KOSATKA_COLOUR"
+ SCR_INT Flag; // "PACKED_MP_INT_KOSATKA_FLAG"
+ SCR_INT LastGuidedMissileUseTime;
+ SCR_INT PAD_0005; // unused
+};
+static_assert(sizeof(SUBMARINE_DATA) == 6 * 8);
+
+struct AUTOSHOP_DATA
+{
+ SCR_INT Index;
+ SCR_INT AccessSetting;
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_INT PAD_0004;
+ SCR_ARRAY ModdingVehicles; // VEHICLE_INDEX, not NETWORK_INDEX
+};
+static_assert(sizeof(AUTOSHOP_DATA) == 8 * 8);
+
+// LS car meet
+struct CAR_CLUB_DATA
+{
+ SCR_INT Flags;
+ SCR_INT Reputation;
+ SCR_INT ReputationLevel;
+ SCR_INT TestTrackAccess; // unused?
+};
+static_assert(sizeof(CAR_CLUB_DATA) == 4 * 8);
+
+// agency
+struct FIXER_HQ_DATA
+{
+ SCR_INT Index;
+ SCR_INT AppearanceBitset;
+ SCR_INT SafeCashValue;
+};
+static_assert(sizeof(FIXER_HQ_DATA) == 3 * 8);
+
+// eclipse blvd garage
+struct MULTI_STOREY_GARAGE_DATA
+{
+ SCR_INT Index; // always one for obvious reasons
+ SCR_INT AppearanceBitset;
+ SCR_INT AppearanceBitset2;
+ SCR_ARRAY GarageTints;
+};
+static_assert(sizeof(MULTI_STOREY_GARAGE_DATA) == 6 * 8);
+
+struct SALVAGE_YARD_DATA
+{
+ SCR_INT Index;
+ SCR_INT PAD_0001;
+ SCR_INT AppearanceBitset;
+ SCR_INT TowTruckColor;
+ SCR_INT TowTruckType; // TODO
+ SCR_INT VehicleRobVehicleIndex;
+ SCR_INT TotalEarnings;
+};
+static_assert(sizeof(SALVAGE_YARD_DATA) == 7 * 8);
+
+struct PROPERTY_DATA
+{
+ SCR_ARRAY PropertyIds; // size 30 -> 31 b3095
+ SCR_BITSETFlags; // I really don't want to indent everything again
+ SCR_INT RingingPlayers; // bitset of players requesting entry into property
+ SCR_INT Index; // the value you pass to the send to apartment TSE
+ SCR_INT Instance;
+ SCR_INT ExteriorIndex;
+ PLAYER_INDEX ExteriorOwner;
+ SCR_ARRAY RingingPlayersState; // 0 = ringing, 1 = accepted, 2 = denied
+ GAMER_HANDLE OwnerHandle; // can be used to bypass RID spoofing when player is inside interior
+ SCR_ARRAY EclipseTheme; // size 30 -> 31 b3095
+ SCR_INT ApartmentType; // normal vs stilt vs eclipse
+ SCR_INT OwnerInstance; // same as Instance in most cases
+ SCR_ARRAY ExecutiveWarehouseInfos;
+ SCR_INT OfficeSafeMoneyMultiplier;
+ SCR_BITSET StyleFlags;
+ SCR_INT PAD_0134; // unused
+ SCR_INT AssistantGreetingChoice;
+ SCR_INT AssistantDialogBitset;
+ SCR_INT AssistantDialogBitset2;
+ SCR_INT LifetimeCargoMissionsComplete; // used for trophy type
+ SCR_INT CasinoChipsMultiplier;
+ SCR_INT AssistantDialogBitset3;
+ SCR_INT AssistantDialogBitset4;
+ SCR_INT AssistantDialogBitset5;
+ SCR_INT AssistantDialogBitset6; // do we REALLY need 6 bitsets for assistant dialog?
+ IE_WAREHOUSE_DATA IEWarehouseData;
+ SCR_INT Garage1DataBitset;
+ SCR_INT Garage2DataBitset;
+ SCR_INT Garage3DataBitset;
+ SCR_INT ModshopDataBitset;
+ SCR_ARRAY FactoryInfos;
+ SCR_INT TotalBunkerResearch;
+ SCR_INT CurrentBunkerResearchProgress;
+ SCR_INT BunkerDecorVariation;
+ SCR_INT MOCBitset;
+ SCR_INT MOCColor; // bitset for some reason
+ uint64_t PAD_0290[2]; // unused
+ SCR_INT GunShopFlags;
+ HANGAR_DATA HangarData;
+ SCR_INT PAD_0299;
+ DEFUNCT_BASE_DATA DefunctBaseData;
+ SCR_INT AvengerInteriorDecorFlags; // "PACKED_MP_INT_ARMORY_AIRCRAFT_INTERIOR_v0"
+ uint64_t PAD_0308[3];
+ BUSINESS_HUB_DATA BusinessHubData;
+ NIGHTCLUB_DATA NightclubData;
+ SCR_INT PAD_0365;
+ SCR_INT TerrorbyteDesign;
+ SCR_INT PAD_0367;
+ SCR_INT AcidLabRadio;
+ SCR_INT TerrorbyteRadio;
+ SCR_INT NanoDroneCooldown;
+ PLAYER_INDEX HostOfInteriorScript;
+ ARENA_GARAGE_DATA ArenaGarageData;
+ SCR_INT ArcadeJukeboxStation; // for simple interior type 17
+ SCR_INT JukeboxFavoritePlaylist;
+ SCR_INT ClubhouseBarCashAmount;
+ SCR_INT DefaultJukeboxStation;
+ SCR_INT FreakshopJukeboxStation;
+ SCR_INT PAD_0386; // TODO
+ SCR_HASH MOCModel; // used by the bunker script to detect exits with MOC
+ SCR_INT PAD_0388; // unused
+ SCR_HASH TerrorbyteModel;
+ SCR_ARRAY PAD_0390; // some property interior stuff
+ uint64_t PAD_0398[4];
+ SCR_INT OfficeGarageModdingVehicleSlot;
+ SCR_INT CurrentOfficeGarageFloor;
+ CASINO_APARTMENT_DATA CasinoApartmentData; // @405 as of 1.67
+ ARCADE_DATA ArcadeData;
+ ARCADE_MACHINES ArcadeMachines;
+ SCR_ARRAY ArcadeMachineSlots;
+ SCR_INT PAD_0478; // TODO
+ SUBMARINE_DATA SubmarineData;
+ AUTOSHOP_DATA AutoShopData;
+ SALVAGE_YARD_DATA SalvageYardData;
+ SCR_ARRAY AutoShopArcadeMachineSlots;
+ CAR_CLUB_DATA CarClubData;
+ FIXER_HQ_DATA FixerHQData;
+ SCR_INT PAD_0503; // not read by the scripts
+ SCR_INT PAD_0504;
+ VEHICLE_INDEX CurrentlyModdingVehicleFixerHQ;
+ MULTI_STOREY_GARAGE_DATA MultiStoreyGarageData; // @507 as of 1.67
+ SCR_INT FreakshopBits; // 0: has weapon workshop, 1: radio enabled
+};
+static_assert(sizeof(PROPERTY_DATA) == 523 * 8);
+
+struct BIKER_CONTRACTS
+{
+ SCR_ARRAY ActiveContractMissions;
+ SCR_INT SelectedContractMission;
+ SCR_BOOL Enabled;
+};
+static_assert(sizeof(BIKER_CONTRACTS) == 7 * 8);
+
+struct NIGHTCLUB_SALE
+{
+ SCR_INT BuyerIndex;
+ SCR_INT NumSoldItems;
+ SCR_INT SaleAmount;
+ uint64_t PAD_0003[2];
+};
+static_assert(sizeof(NIGHTCLUB_SALE) == 5 * 8);
+
+struct ARENA_WAR_DATA
+{
+ SCR_INT PointsTier;
+ SCR_INT SkillLevel;
+ SCR_INT TrinketBitset; // MP_STAT_ARN_BS_TRINKET_SAVED
+};
+static_assert(sizeof(ARENA_WAR_DATA) == 3 * 8);
+
+struct GPBD_FM_Entry
+{
+ SCR_INT CurrentActivity;
+ SCR_INT MissionScriptInstance;
+ SCR_INT PAD_0002; // TODO
+ SCR_INT NumFreeSpectatorSlots;
+ SCR_INT NumPlayersInTransition; // not really
+ SCR_INT NJVSVoteState; // voting screen shown after a mission ends
+ SCR_INT NJVSVoteContentBitset;
+ SCR_BOOL NJVSChoiceMade;
+ SCR_INT NJVSLeaveState; // network error or quit
+ SCR_INT JobPoints; // can be spoofed to change the "JP" value in the player list
+ PLAYER_INDEX NextHost; // transfer transition host when joining next job
+ PLAYLIST_DATA PlaylistData;
+ TEXT_LABEL_63 JobName;
+ SCR_ARRAY ActiveGunRange; // this should have really been an enum lol
+ MP_SCRIPT_DATA MissionScriptData;
+ JOB_SETTINGS JobSettings;
+ SCR_INT FMMCLauncherState;
+ VEHICLE_SELECTION VehicleSelection;
+ SCR_INT JobStartCloudTime; // this is a struct but too lazy to create one
+ SCR_INT ContentHash;
+ SCR_BOOL PAD_0138; // unused
+ SCR_BITSET TutorialBitset;
+ SCR_BITSET GangCallRequestedServices;
+ PLAYER_INDEX GangCallTarget; // can be used to send muggers/hit squad
+ SCR_BITSET GangCallSentServices;
+ SCR_INT TutorialBitset2;
+ TEXT_LABEL_23 PlayingContentUsedId;
+ TEXT_LABEL_23 MatchId;
+ uint64_t PAD_0156[8]; // unused
+ TEXT_LABEL_63 DisplayJobName; // as shown in the playerlist?
+ STRIKE_TEAM StrikeTeam;
+ uint64_t PAD_0185[7]; // pad
+ SCR_INT FMMCState;
+ SCR_INT PAD_0193; // TODO
+ SCR_INT KillStreak;
+ SCR_INT NumSuicides; // deducts RP reward in missions
+ SCR_INT DeathmatchBounty; // "You have been deducted $~1~ for being idle for too long, and you now have a bounty placed on you."
+ SCR_BOOL CollectedBounty;
+ SCR_INT AliveDeathmatchPlayers;
+ SCR_INT WantedLevelFlags;
+ SCR_ARRAY PAD_0201;
+ SCR_INT HairdoShopIndex;
+ SCR_INT PAD_0204;
+ PLAYER_STATS PlayerStats;
+ SCR_INT PAD_265;
+ SCR_INT Mood;
+ PROPERTY_DATA PropertyData; // @267 as of b3095
+ uint64_t PAD_0779[4]; // TODO
+ uint64_t PAD_0783[12]; // no clue what it does but it looks rather interesting
+ SCR_INT AssistedKillFlags;
+ NETWORK_INDEX UnkNetworkId;
+ SCR_BOOL SpawningUnkVehicle;
+ SCR_BOOL MeltdownComplete; // yes, the singleplayer mission "Meltdown" (michael4)
+ SCR_INT UNK_0799;
+ SCR_INT GangAttackTarget; // triggers unique dialog from some phone NPCs
+ SCR_INT ActivePVSlot;
+ PLAYER_INDEX SpectatingPlayer;
+ SCR_INT PAD_0803;
+ SCR_ARRAY ActiveAmbientWeaponPickups; // size 2 -> 3 b3095
+ SCR_ARRAY OfficeMapMarkers;
+ SCR_INT OfficeLargestMoneyThresholdIndex;
+ SCR_ARRAY EnabledOfficeCashPiles;
+ SCR_ARRAY EnabledClubhouseCashPiles;
+ BIKER_CONTRACTS BikerContracts;
+ SCR_INT CasinoWonBitset; // can be used to tamper with the casino PA system
+ uint64_t PAD_0829[2];
+ SCR_BOOL CameraPositionOverriden;
+ SCR_VEC3 OverrideCameraPosition;
+ SCR_INT PAD_0835;
+ SCR_INT HeliRappelFlags;
+ SCR_INT PAD_0837; // some more aircraft flags
+ SCR_BOOL RespawningToPreviousCheckpoint;
+ NIGHTCLUB_SALE NightclubSale;
+ uint64_t PAD_844[11]; // unused, all of them
+ SCR_INT SeatingIndex;
+ ARENA_WAR_DATA ArenaWarData; // @858 as of 1.67
+ uint64_t PAD_0861[2];
+ SCR_INT ApartmentEnterFlags;
+ SCR_VEC3 AvengerMissionStartPosition;
+};
+static_assert(sizeof(GPBD_FM_Entry) == 877 * 8);
+
+struct GPBD_FM
+{
+ SCR_ARRAY Entries;
+};
+static_assert(sizeof(GPBD_FM) == 28065 * 8);
diff --git a/classes/src/script/globals/GPBD_FM_3.hpp b/classes/src/script/globals/GPBD_FM_3.hpp
new file mode 100644
index 0000000000..ad0509536a
--- /dev/null
+++ b/classes/src/script/globals/GPBD_FM_3.hpp
@@ -0,0 +1,357 @@
+#pragma once
+#include "../types.hpp"
+#include "../Timer.hpp"
+#include "../HudColor.hpp"
+#include "../MPScriptData.hpp"
+
+enum class eActivityType
+{
+ HeistPrep = 233,
+ Gunrunning = 180,
+ Sightseer = 142,
+ HeadHunter = 166,
+ BuySpecialCargo = 167,
+ SellSpecialCargo = 168,
+ DefendSpecialCargo = 169,
+ StealVehicle = 178,
+ ExportVehicle = 188,
+ Gunrunning2 = 225,
+ GunrunningSell = 226,
+ GunrunningDefend = 227,
+ BikerSell = 190,
+ BikerDefend = 191,
+ BusinessResupply = 192,
+ Survival = 3,
+ Darts = 14,
+ ArmWresling = 15,
+ GangAttack = 6,
+ PilotSchool = 122,
+ Golf = 11,
+ ShootingRange = 13,
+ Tennis = 12,
+ BaseJump = 8,
+ Deathmatch = 1,
+ ImpromptuDeathmatch = 5,
+ Mission = 0,
+ Race = 2,
+ ExecutiveDeathmatch = 148,
+ MarkedForDeath = 151,
+ PiracyPrevention = 152,
+ MostWanted = 153,
+ AssetRecovery = 157,
+ HostileTakeover = 159,
+ Point2Point = 162,
+ AmphibiousAssault = 216,
+ Velocity = 219,
+ GunsForHire = 185,
+ ByThePound = 182,
+ RippingItUp = 194,
+ RaceToPoint = 189,
+ HitAndRide = 193,
+ CriminalMischief = 205,
+ WeaponOfChoice = 186,
+ FragileGoods = 207,
+ Torched = 208,
+ Outrider = 209,
+ WheelieRider = 210,
+ POW = 183,
+ ExecutiveSearch = 199,
+ StandYourGround = 201,
+ AutoBuyout = 163,
+ DueDiligence = 160,
+ MarketManipulation = 154,
+ CourierService = 155,
+ Skydive = 267
+};
+
+enum class eBossGoonFlags
+{
+ kOneOnOneDM = 4,
+ kJoinSuccess = 7,
+ kJoinFail = 8,
+ kSpectating = 24
+};
+
+enum class eGoonInviteType
+{
+ DEBUG,
+ NEARBY,
+ FRIENDS,
+ CREW,
+ INDIVIDUAL,
+ LOOKING_FOR_WORK
+};
+
+enum class eBossVehicleState
+{
+ NONE,
+ SPAWNED,
+ DESTROYED = 3
+};
+
+enum class eMCRole
+{
+ PROSPECT = -1,
+ VICE_PRESIDENT,
+ ROAD_CAPTAIN,
+ SERGEANT_IN_ARMS,
+ ENFORCER
+};
+
+enum class eClubhouseActivity
+{
+ NONE = -1,
+ DARTS,
+ ARM_WRESTLING
+};
+
+struct MC_STYLE
+{
+ SCR_BOOL Enabled;
+ SCR_INT BossOutfitType;
+ SCR_INT GoonOutfitType;
+ SCR_ARRAY GoonOutfitIndices; // one outfit for each goon
+ SCR_ARRAY GoonOutfitIndicesOverride;
+ SCR_INT PAD_0019;
+ SCR_BOOL HeadgearEnabled;
+ SCR_BOOL EmblemEnabled;
+};
+static_assert(sizeof(MC_STYLE) == 22 * 8);
+
+struct VEHICLE_EXPORT
+{
+ SCR_ARRAY SellingVehicleIndices;
+ SCR_INT PAD_0005; // this is set to zero in all export scripts and never read
+};
+static_assert(sizeof(VEHICLE_EXPORT) == 6 * 8);
+
+struct HANGAR_CARGO
+{
+ SCR_INT PAD_0000; // unused?
+ SCR_ARRAY DeliverableTypes;
+ SCR_INT CargoType;
+};
+static_assert(sizeof(HANGAR_CARGO) == 23 * 8);
+
+struct CASINO_HEIST_PREP
+{
+ SCR_INT PrepIndex;
+ SCR_INT SupportCrewMemberIndex; // only set on preps 1 through 3
+ SCR_INT LoadoutIndex; // only set on prep 1 and 2
+};
+static_assert(sizeof(CASINO_HEIST_PREP) == 3 * 8);
+
+struct LEAVE_IN_HELI
+{
+ SCR_INT Flags;
+ PLAYER_INDEX Owner;
+ SCR_INT SeatIndex;
+};
+static_assert(sizeof(LEAVE_IN_HELI) == 3 * 8);
+
+struct BOSS_GOON
+{
+ PLAYER_INDEX Boss; // leader of CEO/MC
+ SCR_INT TimeBecameBoss;
+ SCR_INT TimeBecameGoon;
+ SCR_INT LastPayTime;
+ SCR_BITSET Flags;
+ SCR_INT Flags2; // TODO
+ SCR_INT Flags3; // TODO
+ SCR_INT TotalBossGoonTime;
+ SCR_ARRAY BossGoonUUID;
+ SCR_ARRAY Goons;
+ SCR_INT GoonsRequestingJoin; // bitset
+ SCR_INT PayGrade;
+ SCR_INT InvitesByBosses; // bitset
+ SCR_INT TransitionBossPersistanceStage;
+ SCR_INT EndBeingGoonReason;
+ SCR_INT PAD_0025; // TODO
+ PLAYER_INDEX JoiningBoss;
+ alignas(8) eGoonInviteType JoinedInviteType;
+ SCR_INT NumBossDeathsSinceLastPay;
+ SCR_VEC3 PAD_0029; // TODO
+ alignas(8) eActivityType UnkActivity;
+ alignas(8) eActivityType CurrentActivity;
+ PLAYER_INDEX JoustTarget;
+ PLAYER_INDEX ExecutiveDeathmatchTarget;
+ MP_SCRIPT_DATA ActiveScript;
+ PLAYER_INDEX PAD_0057;
+ PLAYER_INDEX PAD_0058;
+ alignas(8) eBossVehicleState BossVehicleState;
+ SCR_INT BossVehicleSpawnState;
+ PLAYER_INDEX PlayerInsideBossVehicle;
+ SCR_HASH BossVehicleModel;
+ TIMER LastBossVehicleSpawnTimer;
+ TIMER BossVehicleInvincibleTimer;
+ SCR_VEC3 BossVehicleSpawnedPosition;
+ alignas(8) HudColor BossVehicleHudColor;
+ TEXT_LABEL_15 BossVehicleTextLabel;
+ SCR_INT BossVehicleNetId;
+ MC_STYLE MCStyle;
+ uint64_t PAD_0098[3]; // unused
+ SCR_INT FriendlyFireDisabledPlayers;
+ SCR_INT PiracyPreventionYachtIndex; // not used by the scripts
+ SCR_INT BossGoonMissionLaunchState;
+ SCR_INT ColorSlot;
+ TEXT_LABEL_63 MCName;
+ SCR_INT Language; // can be used to get the system language of player
+ SCR_INT SpawnableBossVehicles;
+ SCR_INT AutoBuyoutDeliveryLocationIndex;
+ SCR_INT AutoBuyoutDeliveryLocationSubIndex;
+ SCR_INT PAD_0125; // unused
+ SCR_ARRAY PAD_0126; // TODO
+ SCR_ARRAY ContrabandPositions; // positions of cargo used to notify players to destroy them when they get near
+ SCR_HASH ContrabandPickupModel;
+ PLAYER_INDEX StealingContrabandVehiclePlayerIndex;
+ SCR_INT PAD_0178; // TODO
+ SCR_HASH ContrabandPickupModel2;
+ SCR_BOOL DestroyedCargo;
+ SCR_INT VIPGameplayDisabledTimer; // @181 as of 1.67
+ SCR_INT SettingUpBusiness;
+ uint64_t PAD_0183[4]; // TODO some unknown contraband struct
+ VEHICLE_EXPORT VehicleExport;
+ uint64_t PAD_0193[12]; // TODO
+ SCR_ARRAY ActiveFreemodeEvents; // force thunder
+ uint64_t PAD_0212[22]; // I'm not even going to bother with this one
+ HANGAR_CARGO HangarCargo;
+ uint64_t PAD_0236[23]; // not going to bother with this one either
+ SCR_ARRAY CasinoDeliverables;
+ SCR_INT CasinoLimoDestination;
+ SCR_BOOL CasinoLimoActive;
+ SCR_BOOL CasinoLuxuryCarActive;
+ SCR_HASH CasinoLuxuryCarModel;
+ CASINO_HEIST_PREP CasinoHeistPrep;
+ SCR_INT CayoPrepIndex;
+ SCR_INT CompanySUVDestination;
+ SCR_BOOL CompanySUVActive;
+ SCR_ARRAY ContrabandIndices; // type of selling cargo
+ SCR_ARRAY VehicleExportIndices; // not sure what this is
+ SCR_INT VehicleExportMissionType; // valid range is 2000 to 2010, 2000 = 0, 2001 = 1 etc
+ SCR_ARRAY VehicleExportSellingIndices;
+ SCR_BOOL PAD_0337; // TODO
+ TEXT_LABEL_63 GangName; // CEO Name
+ TEXT_LABEL_63 ClubhouseName; // cut content?
+ SCR_INT SourcingContrabandType;
+ SCR_INT FragileGoodsMissionType;
+ SCR_INT SalvageMissionType;
+ SCR_INT DoomsdayPrepIndex;
+ SCR_INT VehicleExportIndex; // another one...
+ SCR_INT PAD_0375; // unused
+ SCR_INT BunkerSourceIndex; // check gb_gunrunning func_1540
+ SCR_ARRAY BunkerCargoIndices;
+ uint64_t PAD_0386[5];
+ uint64_t PAD_0391[2]; // unused
+ uint64_t PAD_0393[15]; // smuggler data
+ SCR_INT LastBossWorkTime; // seconds since epoch
+ uint64_t PAD_0409[19];
+ SCR_BOOL IsMC;
+ alignas(8) eMCRole MCRole; // applies to goons only, boss is always the MC president
+ SCR_BOOL FormationFlyingAssist;
+ SCR_INT PAD_0431; // always set to zero and not read
+ SCR_BOOL MCFormationActive;
+ SCR_BOOL MCFormationHelpShown;
+ TIMER MCFormationHealthBonusTimer;
+ TIMER MCFormationLastHealthBonusTimer;
+ TIMER MCFormationBreakTimer;
+ SCR_INT PAD_0440; // unused
+ SCR_BOOL MCFormationAssist;
+ SCR_BOOL MCRidingStyleRelaxed;
+ SCR_FLOAT PAD_0443; // set from a tunable
+ SCR_FLOAT PAD_0444; // set from a tunable
+ uint64_t PAD_0445[16]; // somewhat unused, a few fields are accessed in the business battle script
+ SCR_INT ClothingValue; // total value of equipped clothing used by criminal damage
+ PLAYER_INDEX Adversary; // for common adversary calculations?
+ SCR_HASH ContrabandType; // unknown HASH_ENUM
+ SCR_INT HitAndRideGangType;
+ SCR_BOOL IsMC2;
+ SCR_INT BossGoonVersion;
+ SCR_INT MCTotalContributionPoints;
+ SCR_INT MCContributionPoints;
+ SCR_INT FavoriteBikeStyle; // not read by the scripts
+ SCR_INT GreatestFormationTimeIndex;
+ SCR_INT FormationTime;
+ SCR_BOOL RidingFavoriteMotorcycle;
+ SCR_INT ContrabandSellLocation;
+ SCR_INT BusinessBattleType;
+ SCR_INT PAD_0475;
+ SCR_INT NightclubMissionIndex;
+ SCR_INT NightclubDefendMissionIndex;
+ uint64_t PAD_0478[18]; // TODO
+ SCR_BOOL DoubleActionCacheLocationRevealed;
+};
+static_assert(sizeof(BOSS_GOON) == 498 * 8);
+
+struct MC_STATS
+{
+ SCR_INT FormationTime0;
+ SCR_INT FormationTime1;
+ SCR_INT FormationTime2;
+ SCR_INT FormationTime3;
+ SCR_INT MembersMarkedForDeath;
+ SCR_INT MCKills;
+ SCR_INT MCDeaths;
+ SCR_INT RivalPresidentKills;
+ SCR_INT RivalCEOAndVIPKills;
+ SCR_INT MeleeKills;
+ SCR_INT ClubhouseContractsComplete;
+ SCR_INT ClubhouseContractEarnings;
+ SCR_INT ClubworkCompleted;
+ SCR_INT ClubChallengesCompleted;
+ SCR_INT MemberChallengesCompleted;
+};
+static_assert(sizeof(MC_STATS) == 15 * 8);
+
+
+struct GBPD_FM_3_Entry
+{
+ alignas(8) eActivityType CurrentActivity; // enum is outdated
+ SCR_INT Flags; // TODO
+ alignas(8) eActivityType CurrentFreemodeActivity; // subset of CurrentActivity
+ SCR_INT SeatingFlags;
+ SCR_VEC3 CurrentFreemodeActivityObjectivePosition;
+ SCR_INT VehiclesNearbyActivityObjective; // only used by challenges and checkpoints
+ SCR_BOOL PassiveMode;
+ SCR_BOOL TimeTrialActive; // verify
+ BOSS_GOON BossGoon;
+ uint64_t PAD_507[3]; // unused
+ SCR_INT ScriptEventReplayProtectionCounter;
+ TIMER CoronaForcedLaunchTimer;
+ LEAVE_IN_HELI LeaveInHeli;
+ SCR_INT OfficeDesktopFlags; // bit 0 -> login, bit 1 -> map
+ uint64_t PAD_514[8]; // some IE stuff, most of it is unused
+ SCR_INT IlluminatedClothingState;
+ SCR_INT MatchHistoryId1; // used for telemetry
+ SCR_INT MatchHistoryId2;
+ alignas(8) eClubhouseActivity ClubhouseActivity;
+ SCR_INT ClubhouseFont;
+ SCR_INT ClubhouseColor;
+ SCR_INT ClubhouseEmblem;
+ SCR_BOOL ClubhouseHideSignage;
+ uint64_t PAD_0533[2]; // facility exit
+ uint64_t PAD_0535[6]; // no clue what this is
+ MC_STATS MCStats;
+ uint64_t PAD_0556[29];
+ SCR_HASH ForcedWeapon;
+ SCR_INT HangarCargoMissionLocationIndex;
+ SCR_VEC3 AvengerPosition;
+ SCR_VEC3 TerrorbytePosition;
+ SCR_VEC3 AcidLabPosition;
+ PLAYER_INDEX DeliveringExportVehicleOwner;
+ uint64_t PAD_0597[2]; // TODO
+ SCR_INT BountyAmount; // values above 10000 will prevent payout
+ PLAYER_INDEX BountyPlacedBy;
+ SCR_INT PAD_0601; // unused, set to -1 by business_battles_sell and never read
+ SCR_INT CurrentlyUsingArenaTurretIndex; // works similar to the vars found in GlobalPlayerBD
+ SCR_INT CurrentlyUsingArenaTurretActivatedTime;
+ SCR_INT CasinoStoryProgress;
+ SCR_INT CasinoFlowProgress;
+ SCR_ARRAY DailyObjectiveFlags; // @607 as of 1.67
+};
+static_assert(sizeof(GBPD_FM_3_Entry) == 609 * 8);
+
+struct GPBD_FM_3
+{
+ SCR_ARRAY Entries;
+};
+static_assert(sizeof(GPBD_FM_3) == 19489 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GPBD_Kicking.hpp b/classes/src/script/globals/GPBD_Kicking.hpp
new file mode 100644
index 0000000000..d926d33fd3
--- /dev/null
+++ b/classes/src/script/globals/GPBD_Kicking.hpp
@@ -0,0 +1,17 @@
+#pragma once
+#include "../types.hpp"
+
+struct GPBD_KickingEntry
+{
+ SCR_ARRAY KickVotes; // players you are voting to kick (array of bool)
+ SCR_ARRAY KickWarningsShown;
+ SCR_BOOL WillBeKickedSoon;
+ SCR_ARRAY PlayersToBeKickedSoon;
+};
+static_assert(sizeof(GPBD_KickingEntry) == 100 * 8);
+
+struct GPBD_Kicking
+{
+ SCR_ARRAY Entries;
+};
+static_assert(sizeof(GPBD_Kicking) == 3201 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GPBD_MissionName.hpp b/classes/src/script/globals/GPBD_MissionName.hpp
new file mode 100644
index 0000000000..22bb3f4bc4
--- /dev/null
+++ b/classes/src/script/globals/GPBD_MissionName.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include "../types.hpp"
+
+struct GPBD_MissionName
+{
+ SCR_ARRAY MissionNames;
+};
+static_assert(sizeof(GPBD_MissionName) == 513 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GSBD.hpp b/classes/src/script/globals/GSBD.hpp
new file mode 100644
index 0000000000..f1ea0bada5
--- /dev/null
+++ b/classes/src/script/globals/GSBD.hpp
@@ -0,0 +1,94 @@
+#pragma once
+#include "../types.hpp"
+#include "GlobalPlayerBD.hpp"
+
+struct IMPOUND_VEHICLE_INFO
+{
+ SCR_INT ImpoundId;
+ SCR_BOOL OccupiedCheckDone;
+ SCR_INT EntityAreaHandle;
+ SCR_INT TimeCreated;
+};
+static_assert(sizeof(IMPOUND_VEHICLE_INFO) == 4 * 8);
+
+struct CEO_COLOR
+{
+ PLAYER_INDEX Owner;
+ SCR_INT Color;
+};
+static_assert(sizeof(CEO_COLOR) == 2 * 8);
+
+struct CEO_COLORS
+{
+ SCR_ARRAY CeoColorIndices;
+ SCR_ARRAY CeoColorIndices2;
+ SCR_ARRAY CeoColors;
+ SCR_INT PAD_0065;
+ uint64_t PAD_0066[19];
+ SCR_INT PAD_0085; // added b3095 ("Press ~INPUT_CONTEXT~ to contact Jamal and begin stealing bolt cutters for The Cargo Ship Robbery" mission variation)
+};
+static_assert(sizeof(CEO_COLORS) == 86 * 8);
+
+struct SMPL_INTERIOR_DATA_SERVER
+{
+ SCR_INT PAD_0000; // unused
+ SCR_ARRAY PlayerInteriorInstances;
+ SCR_ARRAY PlayerInteriorIds; // used solely for telemetry
+ SCR_INT PlayerInteriorCreationRequestBitset;
+ SCR_ARRAY PlayerOwnerBitset;
+ SCR_INT PlayerInteriorRemovalRequestBitset;
+ SCR_ARRAY PlayerInteriorCreationTimes;
+ SCR_ARRAY PlayerInteriorSimpleInteriorTypes;
+ SCR_ARRAY PlayerInteriorIsOwnerless;
+ SCR_ARRAY PlayerInteriorOwners;
+};
+static_assert(sizeof(SMPL_INTERIOR_DATA_SERVER) == 234 * 8);
+
+struct LEAVE_CLUBHOUSE_SERVER
+{
+ SCR_ARRAY Identifiers;
+ SCR_ARRAY ExitLocations;
+ SCR_ARRAY ExitLocationSlots;
+};
+static_assert(sizeof(LEAVE_CLUBHOUSE_SERVER) == 99 * 8);
+
+struct IE_DELIVERY_INFO
+{
+ PLAYER_INDEX Player_;
+ SCR_HASH VehicleModel;
+ PLAYER_INDEX ContrabandOwner;
+ SCR_INT TimeCreated;
+ SCR_BOOL PAD_0004;
+};
+static_assert(sizeof(IE_DELIVERY_INFO) == 5 * 8);
+
+struct GSBD
+{
+ alignas(8) eFreemodeState FreemodeState;
+ SCR_INT SessionToken; // time when freemode had started for the script host
+ SCR_ARRAY ImpoundVehicleInfos;
+ SCR_ARRAY SpawnPositions;
+ SCR_ARRAY SpawnPositionCreationTimes;
+ SCR_ARRAY SpawnPositionsValid;
+ SCR_ARRAY PAD_0294;
+ SCR_ARRAY SpawnPositionTokens;
+ SCR_INT SpawnPositionCounter;
+ SCR_ARRAY RespawnVehicles;
+ SCR_ARRAY RespawnVehicleSeats;
+ SCR_ARRAY MorsMutualSpawnSlots;
+ SCR_INT MorsMutualSpawnPlayersBitset;
+ uint64_t PAD_0461[353]; // TODO
+ SCR_BOOL CopTimerOn; // cut CnC content
+ SCR_BOOL CrookTimerOn;
+ SCR_BOOL PAD_0816; // always set to FALSE
+ SCR_INT PAD_0817; // unused
+ CEO_COLORS CeoColors;
+ SMPL_INTERIOR_DATA_SERVER SimpleInteriorData;
+ LEAVE_CLUBHOUSE_SERVER LeaveClubhouse;
+ SCR_ARRAY IEDeliveryInfos;
+ SCR_INT PAD_1397;
+ NETWORK_INDEX IAATurretCameraVehicleId; // used by DDH act 1
+ uint64_t PAD_1399[97];
+ SCR_INT CayoPericoStrandedAnimalChoice;
+};
+static_assert(sizeof(GSBD) == 1498 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GSBD_BlockB.hpp b/classes/src/script/globals/GSBD_BlockB.hpp
new file mode 100644
index 0000000000..711648c88f
--- /dev/null
+++ b/classes/src/script/globals/GSBD_BlockB.hpp
@@ -0,0 +1,96 @@
+#pragma once
+#include "../types.hpp"
+
+
+enum class eDeliverableState
+{
+ INVALID = -1,
+ INITIAL,
+ DELIVERED
+};
+
+struct PLAYER_MISSION_INFO
+{
+ SCR_INT State;
+ SCR_INT Index; // GSBD_MissionRequest index
+};
+static_assert(sizeof(PLAYER_MISSION_INFO) == 2 * 8);
+
+struct CRATE_DROP
+{
+ SCR_INT PAD_0000; // unused
+ SCR_BOOL EnableCrateDrops; // tries to trigger strange last gen stuff unsuccessfully
+ uint64_t PAD_0003[2]; // unused
+};
+static_assert(sizeof(CRATE_DROP) == 4 * 8);
+
+struct DELIVERABLE_ID
+{
+ PLAYER_INDEX Owner;
+ SCR_INT Id; // "FMDeliverableID"
+};
+static_assert(sizeof(DELIVERABLE_ID) == 2 * 8);
+
+struct DELIVERABLE_SCRIPT_INFO
+{
+ SCR_HASH Hash_;
+ uint64_t PAD_0001[2]; // unused
+};
+static_assert(sizeof(DELIVERABLE_SCRIPT_INFO) == 3 * 8);
+
+struct UNK_0962
+{
+ PLAYER_INDEX PAD_0000;
+ SCR_ARRAY PAD_0001;
+ SCR_ARRAY PAD_0020;
+};
+static_assert(sizeof(UNK_0962) == 75 * 8);
+
+struct DELIVERABLE
+{
+ alignas(8) eDeliverableState State;
+ DELIVERABLE_ID DeliverableId;
+ SCR_INT Type;
+ SCR_INT PAD_0004; // this is always set to zero
+ SCR_ARRAY DroppedOffLocations; // "activeDropOff is not the same as sctiptDropOff"
+ DELIVERABLE_SCRIPT_INFO ScriptInfo;
+ SCR_INT NumDropOffs;
+};
+static_assert(sizeof(DELIVERABLE) == 15 * 8);
+
+// "FREEMODE_DELIVERY_SERVER_ADD_DELIVERABLE_ID" "_FREEMODE_DELIVERY_MAINTAIN_SERVER"
+struct FREEMODE_DELIVERY
+{
+ SCR_BOOL Initialized;
+ SCR_ARRAY Deliverables;
+ SCR_ARRAY PAD_0962; // TODO
+};
+static_assert(sizeof(FREEMODE_DELIVERY) == 1713 * 8);
+
+struct GLOBAL_CLUB_INFO
+{
+ uint64_t PAD_0000[16];
+};
+static_assert(sizeof(GLOBAL_CLUB_INFO) == 16 * 8);
+
+struct GSBD_BlockB
+{
+ SCR_INT MissionLauncherInitializedBitset;
+ PLAYER_INDEX ScriptHost;
+ SCR_INT PAD_0002;
+ SCR_BOOL PAD_0003; // forces a team update thingy
+ SCR_ARRAY PlayerMissionInfos;
+ SCR_INT HostMigrationCounter;
+ uint64_t PAD_0080[14]; // unused
+ CRATE_DROP CrateDrop;
+ uint64_t PAD_0088[6]; // unused
+ uint64_t PAD_0094[33]; // ???
+ uint64_t PAD_0127[65]; // even more strange stuff (cut content?)
+ SCR_ARRAY TurretCooldownTimers;
+ FREEMODE_DELIVERY FreemodeDelivery;
+ SCR_ARRAY GlobalClubInfos;
+ SCR_ARRAY CarMeetModShopSlotIndices;
+ SCR_ARRAY CarMeetModShopOccupiedGoons;
+ SCR_ARRAY, 32>CarMeetModShopOccupiedVehicleSlots;
+};
+static_assert(sizeof(GSBD_BlockB) == 2156 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GSBD_FM.hpp b/classes/src/script/globals/GSBD_FM.hpp
new file mode 100644
index 0000000000..a0449ab3f0
--- /dev/null
+++ b/classes/src/script/globals/GSBD_FM.hpp
@@ -0,0 +1,66 @@
+#pragma once
+#include "../types.hpp"
+
+struct PLAYER_BOUNTY
+{
+ SCR_BOOL HasBounty;
+ SCR_INT BountyAmount;
+ SCR_INT PAD_0002; // unused
+};
+static_assert(sizeof(PLAYER_BOUNTY) == 3 * 8);
+
+struct ACTIVE_CONTACT_SERVICE
+{
+ SCR_INT Id;
+ PLAYER_INDEX Target;
+ SCR_BOOL Bounty; // unknown usage
+ SCR_INT Flags;
+};
+static_assert(sizeof(ACTIVE_CONTACT_SERVICE) == 4 * 8);
+
+struct WEAPON_PICKUPS
+{
+ SCR_INT LastUnkWeaponPickupTime;
+ SCR_INT LastMeleeWeaponPickupTime;
+ SCR_INT LastProjectilePickupTime;
+ SCR_INT LastGunPickupTime;
+ SCR_ARRAY Indices; // size increased in b3095 (62 -> 95)
+ SCR_ARRAY Owners;
+ SCR_INT SpawnCounter;
+ SCR_INT AmmoCount;
+};
+static_assert(sizeof(WEAPON_PICKUPS) == 198 * 8);
+
+struct BIKER_CONTRACTS_SERVER
+{
+ SCR_ARRAY ActiveContracts;
+ SCR_ARRAY ContractCompleteCount;
+ SCR_INT CompletedContractBitset;
+ SCR_INT LastContractRefreshTime;
+};
+static_assert(sizeof(BIKER_CONTRACTS_SERVER) == 10 * 8);
+
+struct GSBD_FM
+{
+ SCR_ARRAY ModelSwapBits;
+ SCR_INT PAD_0003; // unused
+ SCR_ARRAY PlayerBounties;
+ uint64_t PAD_0101[5]; // unused
+ SCR_ARRAY MuggingPlayers; // 0 = mugger, 1 = merryweather mercs
+ SCR_ARRAY MuggedPlayers;
+ uint64_t PAD_0112[4]; // unused
+ SCR_ARRAY PAD_0116; // TODO
+ SCR_INT ShopProcessingBitset;
+ SCR_ARRAY ActiveContactServiceBitsets;
+ SCR_ARRAY ActiveContactServices;
+ PLAYER_INDEX SpectatorTVWantedPlayer;
+ SCR_BOOL SpectatorTVWantedClosing;
+ SCR_BOOL SpectatorTVWantedActive;
+ uint64_t PAD_0390[2]; // not read by the scripts
+ SCR_INT PAD_0392; // TODO
+ uint64_t PAD_0393[6]; // TODO
+ WEAPON_PICKUPS WeaponPickups;
+ BIKER_CONTRACTS_SERVER BikerContracts;
+ SCR_ARRAY DoubleActionCacheLocationRevealed;
+};
+static_assert(sizeof(GSBD_FM) == 642 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GSBD_Kicking.hpp b/classes/src/script/globals/GSBD_Kicking.hpp
new file mode 100644
index 0000000000..93d4367b85
--- /dev/null
+++ b/classes/src/script/globals/GSBD_Kicking.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include "../types.hpp"
+
+struct GSBD_Kicking
+{
+ SCR_ARRAY KickedPlayers;
+};
+static_assert(sizeof(GSBD_Kicking) == 33 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GSBD_PropertyInstances.hpp b/classes/src/script/globals/GSBD_PropertyInstances.hpp
new file mode 100644
index 0000000000..1c44137ec1
--- /dev/null
+++ b/classes/src/script/globals/GSBD_PropertyInstances.hpp
@@ -0,0 +1,11 @@
+#pragma once
+#include "../types.hpp"
+
+// this is why your apartment generally takes years to load
+struct GSBD_PropertyInstances
+{
+ SCR_ARRAY PropertyOwners;
+ uint64_t PAD_0417[14]; // unused
+ SCR_ARRAY PropertyOwnerInstances;
+};
+static_assert(sizeof(GSBD_PropertyInstances) == 464 * 8);
\ No newline at end of file
diff --git a/classes/src/script/globals/GlobalPlayerBD.hpp b/classes/src/script/globals/GlobalPlayerBD.hpp
new file mode 100644
index 0000000000..706b326f18
--- /dev/null
+++ b/classes/src/script/globals/GlobalPlayerBD.hpp
@@ -0,0 +1,669 @@
+#pragma once
+#include "../types.hpp"
+#include "../MPScriptData.hpp"
+
+enum class eFreemodeState
+{
+ NONE = 0,
+ UNK_2 = 2,
+ RUNNING = 4,
+ CLOSING = 5,
+ UNK_10 = 10,
+ UNK_11 = 11
+};
+
+enum class eMissionType
+{
+ NONE,
+ MISSION,
+ HEIST,
+ UNK_3,
+ ADVERSARY_MODE,
+ LAST_TEAM_STANDING,
+ CAPTURE,
+ HEIST_SETUP,
+ UNK_8, // FMMC_RSTAR_MCP
+ UNKNOWN // everything else
+};
+
+enum class eAnimationBitset
+{
+ kCashRainActive = 12,
+ kChampagneSprayActive = 13
+};
+
+enum class eBlipFlags
+{
+ // 0 is unused
+ kVisibleOnCutscene = 1,
+ kFlashMinimapDisplay = 2,
+ kFlashBlip = 3,
+ kMicroLightOTRActive = 4,
+ kSkipTutorialSessionChecks = 5,
+ kHideOnMinimap = 6, // needs testing
+ kHideOnMinimapWhenInterior = 7, // needs testing
+ kHideOnMinimapWhenBigMapActive = 9, // needs testing
+ kDontUsePassiveBlip = 21,
+ kUseRampageBlip = 24,
+ kHideWhenFading = 25
+};
+
+enum class eBlipType
+{
+ ON_FOOT,
+ TANK,
+ PLAYER_JET,
+ PLAYER_PLANE,
+ PLAYER_HELI,
+ PLAYER_GUNCAR,
+ PLAYER_BOAT,
+ ROCKET_VOLTIC,
+ TECHNICAL,
+ RUINER_2000,
+ DUNE_BUGGY,
+ PHANTOM_WEDGE,
+ ARMORED_BOXVILLE, // boxville5
+ WASTELANDER,
+ QUAD,
+ APC,
+ OPPRESSOR_MK_1,
+ HALF_TRACK,
+ DUNE_FAV,
+ WEAPONIZED_TAMPA,
+ AA_TRAILER,
+ ALPHA_Z1,
+ BOMBUSHKA,
+ HAVOK,
+ HOWARD,
+ HUNTER,
+ MICROLIGHT,
+ MOGUL,
+ MOLOTOK,
+ NOKOTA,
+ PYRO,
+ ROGUE,
+ STARLING,
+ SEABREEZE,
+ TULA,
+ STROMBERG,
+ DELUXO,
+ THRUSTER,
+ KHANJALI,
+ RIOT_VAN,
+ VOLATOL,
+ BARRAGE,
+ AKULA,
+ CHERNOBOG,
+ AVENGER,
+ TURRETED_LIMO,
+ SEA_SPARROW,
+ CARACARA,
+ PARTY_BUS,
+ TERRORBYTE,
+ MENACER,
+ SCRAMJET,
+ POUNDER_CUSTOM,
+ MULE_CUSTOM,
+ SPEEDO_CUSTOM,
+ OPPRESSOR_MK_2,
+ STRIKEFORCE,
+ ARENA_BRUISER,
+ ARENA_BRUTUS,
+ ARENA_CERBERUS,
+ ARENA_DEATHBIKE,
+ ARENA_DOMINATOR,
+ ARENA_IMPALER,
+ ARENA_IMPERATOR,
+ ARENA_ISSI,
+ ARENA_SASQUATCH,
+ ARENA_SCARAB,
+ ARENA_SLAMVAN,
+ ARENA_ZR380,
+ MINI_SUB,
+ SPARROW,
+ FOLDING_WING_JET,
+ GANG_BIKE,
+ MILITARY_QUAD,
+ SQUADDIE, // SQUADEE
+ CAYO_DINGHY,
+ WINKY,
+ PATROL_BOAT,
+ ANNIHILATOR,
+ KART_RETRO,
+ KART_MODERN,
+ MILITARY_TRUCK,
+ SUBMARINE,
+ CHAMPION,
+ BUFFALO_STX,
+ DEITY, // why does this have a blip?
+ JUBILEE,
+ GRANGER_3600LX,
+ PATRIOT_MILSPEC,
+ ARMS_DEALING_AIR, // requires some flag to be set
+ BRICKADE_6X6
+};
+
+enum class ePlayerStateFlags
+{
+ kScreenFadingOut = 0,
+ kScreenFadedOut = 1,
+ kCinematicNewsChannelActive = 2,
+ kRepeatingPreviousCheckpoint = 3,
+ kCarModIntro = 4,
+ kPlayerSwitchStateAscent = 5,
+ kPlayerSwitchStateInClouds = 6,
+ kPlayerSwitchStatePan = 7,
+ kPlayerSwitchStateDescent = 8,
+ kModshopActive = 9,
+ kModshopExitingVehicle = 10,
+ kSpectating = 28,
+ kBeastActive = 29,
+ kPlayerNotInSCTV = 30,
+ kPlayerInSCTV = 31
+};
+
+enum class eActivityFlags
+{
+ kWatchingMovie = 0,
+ kInGangAttack = 1,
+ kImpromptuRace = 2,
+ kCrateDrop = 4, // tf is this? "~s~A plane is on its way to drop a Crate ~HUD_COLOUR_GREEN~~BLIP_CRATEDROP~ ~s~which contains useful equipment. Be the first to collect it."
+ kDeliveringSimeonVehicle = 6,
+ kInLapDance = 7,
+ kHoldUpTutorial = 8,
+ kJoyrider = 9, // uh what is this?
+ kCarModTutorial = 10,
+ kMissionLauncher = 11, // ???
+ kLesterCutsceneActive = 12,
+ kTrevorCutsceneActive = 13,
+ kHeistIntro = 14,
+ kPlaneTakedown = 15, // not sure what this is
+ kDistractCops = 16, // "Great. Thank you for your help. Now some horrible criminals are in jail for a crime they did commit and it's all your fault!!" ???
+ kDestroyVehicle = 17, // ???
+ kPartakingInHotTarget = 18,
+ kPartakingInKillList = 19,
+ kTimeTrialStarted = 21,
+ kPartakingInCheckpoints = 22,
+ kPartakingInChallenge = 23,
+ kPennedInActive = 24,
+ kRCTimeTrialStarted = 25,
+ kPartakingInHotProperty = 27,
+ kPartakingInKingOfTheCastle = 29,
+ kPartakingInCriminalDamage = 30,
+ kLowriderIntro = 31
+};
+
+enum class eGamerTagFlags
+{
+ kShowPackageCount = 13,
+ kFadeOutGamerTag = 17,
+ kGangCEO = 19,
+ kGangBiker = 20
+}; // TODO!
+
+enum class eOrbitalBitset
+{
+ kOrbitalCannonActive = 0,
+ kWatchingMovie = 1, // not a typo, the orbital cannon script needs to know if you are inside a movie theater for some strange reason
+ kCutsceneOrInterior = 2,
+ kTransactionPending = 3
+};
+
+enum class eArcadeGameBitset
+{
+ kArcadeMachineActivated = 0,
+ kLoveMeterActivated = 1,
+ kLoveMeterAnimationGenderDecided = 2
+};
+
+enum class eOutOfSightFlags
+{
+ kOutOfSightEnabled = 0,
+ kOutOfSightActive = 1, // this controls whether you appear on radar or not
+ kHelpDisplayed = 2,
+ kDamagedPlayerOutsideOrganization = 3
+};
+
+enum class eSimpleInteriorIndex
+{
+ SIMPLE_INTERIOR_INVALID = -1,
+ SIMPLE_INTERIOR_WAREHOUSE_1,
+ SIMPLE_INTERIOR_WAREHOUSE_2,
+ SIMPLE_INTERIOR_WAREHOUSE_3,
+ SIMPLE_INTERIOR_WAREHOUSE_4,
+ SIMPLE_INTERIOR_WAREHOUSE_5,
+ SIMPLE_INTERIOR_WAREHOUSE_6,
+ SIMPLE_INTERIOR_WAREHOUSE_7,
+ SIMPLE_INTERIOR_WAREHOUSE_8,
+ SIMPLE_INTERIOR_WAREHOUSE_9,
+ SIMPLE_INTERIOR_WAREHOUSE_10,
+ SIMPLE_INTERIOR_WAREHOUSE_11,
+ SIMPLE_INTERIOR_WAREHOUSE_12,
+ SIMPLE_INTERIOR_WAREHOUSE_13,
+ SIMPLE_INTERIOR_WAREHOUSE_14,
+ SIMPLE_INTERIOR_WAREHOUSE_15,
+ SIMPLE_INTERIOR_WAREHOUSE_16,
+ SIMPLE_INTERIOR_WAREHOUSE_17,
+ SIMPLE_INTERIOR_WAREHOUSE_18,
+ SIMPLE_INTERIOR_WAREHOUSE_19,
+ SIMPLE_INTERIOR_WAREHOUSE_20,
+ SIMPLE_INTERIOR_WAREHOUSE_21,
+ SIMPLE_INTERIOR_WAREHOUSE_22,
+ SIMPLE_INTERIOR_FACTORY_METH_1,
+ SIMPLE_INTERIOR_FACTORY_WEED_1,
+ SIMPLE_INTERIOR_FACTORY_CRACK_1,
+ SIMPLE_INTERIOR_FACTORY_MONEY_1,
+ SIMPLE_INTERIOR_FACTORY_DOCUMENTS_1,
+ SIMPLE_INTERIOR_FACTORY_METH_2,
+ SIMPLE_INTERIOR_FACTORY_WEED_2,
+ SIMPLE_INTERIOR_FACTORY_CRACK_2,
+ SIMPLE_INTERIOR_FACTORY_MONEY_2,
+ SIMPLE_INTERIOR_FACTORY_DOCUMENTS_2,
+ SIMPLE_INTERIOR_FACTORY_METH_3,
+ SIMPLE_INTERIOR_FACTORY_WEED_3,
+ SIMPLE_INTERIOR_FACTORY_CRACK_3,
+ SIMPLE_INTERIOR_FACTORY_MONEY_3,
+ SIMPLE_INTERIOR_FACTORY_DOCUMENTS_3,
+ SIMPLE_INTERIOR_FACTORY_METH_4,
+ SIMPLE_INTERIOR_FACTORY_WEED_4,
+ SIMPLE_INTERIOR_FACTORY_CRACK_4,
+ SIMPLE_INTERIOR_FACTORY_MONEY_4,
+ SIMPLE_INTERIOR_FACTORY_DOCUMENTS_4,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_POLICE_STATION,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_MC_CLUBHOUSE,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_ROCKFORD,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_PILLBOX,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_ALTA,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_BURTON,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_PALETO,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_GRAND_SENORA,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BANK_CHUMASH,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_ROCKCLUB,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_CHICKEN_FACTORY,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_CHICKEN_FACTORY_PART_2,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_CHICKEN_FACTORY_PART_3,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_CHICKEN_FACTORY_PART_4,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_FARMHOUSE,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_HEIST_YACHT,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_RECYCLING_PLANT,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BIOLAB,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_1,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_2,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_3,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_4,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_5,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_6,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_7,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_8,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_9,
+ SIMPLE_INTERIOR_IE_WAREHOUSE_10,
+ SIMPLE_INTERIOR_BUNKER_1,
+ SIMPLE_INTERIOR_BUNKER_2,
+ SIMPLE_INTERIOR_BUNKER_3,
+ SIMPLE_INTERIOR_BUNKER_4,
+ SIMPLE_INTERIOR_BUNKER_5,
+ SIMPLE_INTERIOR_BUNKER_6,
+ SIMPLE_INTERIOR_BUNKER_7,
+ SIMPLE_INTERIOR_BUNKER_9,
+ SIMPLE_INTERIOR_BUNKER_10,
+ SIMPLE_INTERIOR_BUNKER_11,
+ SIMPLE_INTERIOR_BUNKER_12,
+ SIMPLE_INTERIOR_ARMORY_TRUCK_1,
+ SIMPLE_INTERIOR_CREATOR_TRAILER_1,
+ SIMPLE_INTERIOR_HANGAR_1,
+ SIMPLE_INTERIOR_HANGAR_2,
+ SIMPLE_INTERIOR_HANGAR_3,
+ SIMPLE_INTERIOR_HANGAR_4,
+ SIMPLE_INTERIOR_HANGAR_5,
+ SIMPLE_INTERIOR_ARMORY_AIRCRAFT_1,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_1,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_2,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_3,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_4,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_6,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_7,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_8,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_9,
+ SIMPLE_INTERIOR_DEFUNCT_BASE_10,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_MEDIUM_GARAGE,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_LOWEND_STUDIO,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_MIDEND_APARTMENT,
+ SIMPLE_INTERIOR_CREATOR_AIRCRAFT_1,
+ SIMPLE_INTERIOR_HUB_LA_MESA,
+ SIMPLE_INTERIOR_HUB_MISSION_ROW,
+ SIMPLE_INTERIOR_HUB_STRAWBERRY_WAREHOUSE,
+ SIMPLE_INTERIOR_HUB_WEST_VINEWOOD,
+ SIMPLE_INTERIOR_HUB_CYPRESS_FLATS,
+ SIMPLE_INTERIOR_HUB_LSIA_WAREHOUSE,
+ SIMPLE_INTERIOR_HUB_ELYSIAN_ISLAND,
+ SIMPLE_INTERIOR_HUB_DOWNTOWN_VINEWOOD,
+ SIMPLE_INTERIOR_HUB_DEL_PERRO_BUILDING,
+ SIMPLE_INTERIOR_HUB_VESPUCCI_CANALS,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_SHERIFF,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_SHERIFF2,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_UNION_DEPOSITORY_CARPARK,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_SIMEON_SHOWROOM,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_ABATTOIR,
+ SIMPLE_INTERIOR_HACKER_TRUCK,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_JEWEL_STORE,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_LIFE_INVADER,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_DJ_YACHT,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_MELANOMA_GARAGE,
+ SIMPLE_INTERIOR_ARENA_GARAGE_1,
+ SIMPLE_INTERIOR_CASINO,
+ SIMPLE_INTERIOR_CASINO_APT,
+ SIMPLE_INTERIOR_CASINO_VAL_GARAGE,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_HAYES_AUTOS,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_METH_LAB,
+ SIMPLE_INTERIOR_ARCADE_PALETO_BAY,
+ SIMPLE_INTERIOR_ARCADE_GRAPESEED,
+ SIMPLE_INTERIOR_ARCADE_DAVIS,
+ SIMPLE_INTERIOR_ARCADE_WEST_VINEWOOD,
+ SIMPLE_INTERIOR_ARCADE_ROCKFORD_HILLS,
+ SIMPLE_INTERIOR_ARCADE_LA_MESA,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_FIB_BUILDING,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_BIOLAB_AND_TUNNEL,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_FOUNDRY,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_MAX_RENDA,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER_PART_2,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER_PART_3,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER_PART_4,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER_PART_5,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_AIRCRAFT_CARRIER_PART_6,
+ SIMPLE_INTERIOR_RESTRICTED_INTERIOR_OMEGA,
+ SIMPLE_INTERIOR_SOLOMONS_OFFICE,
+ SIMPLE_INTERIOR_CASINO_NIGHTCLUB,
+ SIMPLE_INTERIOR_SUBMARINE,
+ SIMPLE_INTERIOR_MUSIC_STUDIO,
+ SIMPLE_INTERIOR_AUTO_SHOP_LA_MESA,
+ SIMPLE_INTERIOR_AUTO_SHOP_STRAWBERRY,
+ SIMPLE_INTERIOR_AUTO_SHOP_BURTON,
+ SIMPLE_INTERIOR_AUTO_SHOP_RANCHO,
+ SIMPLE_INTERIOR_AUTO_SHOP_MISSION_ROW,
+ SIMPLE_INTERIOR_CAR_MEET,
+ SIMPLE_INTERIOR_FIXER_HQ_HAWICK,
+ SIMPLE_INTERIOR_FIXER_HQ_ROCKFORD,
+ SIMPLE_INTERIOR_FIXER_HQ_SEOUL,
+ SIMPLE_INTERIOR_FIXER_HQ_VESPUCCI,
+ SIMPLE_INTERIOR_ACID_LAB,
+ SIMPLE_INTERIOR_JUGGALO_HIDEOUT,
+ SIMPLE_INTERIOR_MULTISTOREY_GARAGE,
+ SIMPLE_INTERIOR_SALVAGE_YARD_LA_PUERTA,
+ SIMPLE_INTERIOR_SALVAGE_YARD_MURIETTA_HEIGHTS,
+ SIMPLE_INTERIOR_SALVAGE_YARD_PALETO_BAY,
+ SIMPLE_INTERIOR_SALVAGE_YARD_SANDY_SHORES,
+ SIMPLE_INTERIOR_SALVAGE_YARD_STRAWBERRY,
+};
+
+struct JOB_STATS
+{
+ SCR_INT Wins;
+ SCR_INT Losses;
+ SCR_INT Kills;
+ SCR_INT Deaths;
+ SCR_INT PAD_0004; // unused
+};
+
+struct JOB_BET
+{
+ SCR_INT PAD_0000; // TODO
+ SCR_INT Amount;
+};
+
+struct MISSION_BETS
+{
+ SCR_INT Identifier; // a random integer between 100 and 10000000
+ JOB_STATS Stats;
+ SCR_ARRAY