diff --git a/classes.cpp b/classes.cpp index 7956581..b7f5c13 100644 --- a/classes.cpp +++ b/classes.cpp @@ -31,6 +31,7 @@ #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" @@ -201,6 +202,7 @@ #include "vehicle/CVehicleModelInfo.hpp" #include "vehicle/CVehicleDriveByMetadataMgr.hpp" #include "vehicle/CVehicleSeatMetadataMgr.hpp" +#include "vehicle/CTrainConfig.hpp" #include "weapon/CAmmoInfo.hpp" #include "weapon/CAmmoProjectileInfo.hpp" #include "weapon/CAmmoRocketInfo.hpp" diff --git a/game_files/CGameConfig.hpp b/game_files/CGameConfig.hpp new file mode 100644 index 0000000..1df087b --- /dev/null +++ b/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/netsync/nodes/pickup/CPickupCreationDataNode.hpp b/netsync/nodes/pickup/CPickupCreationDataNode.hpp index c2a00bc..f1ded50 100644 --- a/netsync/nodes/pickup/CPickupCreationDataNode.hpp +++ b/netsync/nodes/pickup/CPickupCreationDataNode.hpp @@ -14,7 +14,7 @@ class CPickupCreationDataNode : CProjectBaseSyncDataNode uint32_t m_amount; //0x011C uint32_t m_custom_model; //0x0120 uint32_t m_life_time; //0x0124 - uint32_t m_weapon_component[11]; //0x0128 + 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 diff --git a/netsync/nodes/player/CPlayerAppearanceDataNode.hpp b/netsync/nodes/player/CPlayerAppearanceDataNode.hpp index 14d879b..708027f 100644 --- a/netsync/nodes/player/CPlayerAppearanceDataNode.hpp +++ b/netsync/nodes/player/CPlayerAppearanceDataNode.hpp @@ -6,88 +6,88 @@ class CPlayerAppearanceDataNode : CSyncDataNodeInfrequent { public: - uint32_t unk_0xC0[56]; //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 unk_0x3F8; //0x3F8 - float unk_0x3FC; //0x3FC - uint32_t unk_0x400; //0x400 - uint32_t unk_0x404; //0x404 - uint32_t unk_0x408; //0x408 - uint32_t unk_0x40C; //0x40C - uint32_t unk_0x410; //0x410 - bool unk_0x414; //0x414 - bool unk_0x415; //0x415 - bool unk_0x416; //0x416 - bool unk_0x417; //0x417 - bool unk_0x418; //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 + uint32_t unk_0xC0[56]; //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) == 0x45C); #pragma pack(pop) diff --git a/script/scrNativeHandler.hpp b/script/scrNativeHandler.hpp index 95a412c..ddf1980 100644 --- a/script/scrNativeHandler.hpp +++ b/script/scrNativeHandler.hpp @@ -5,57 +5,57 @@ namespace rage { - class scrNativeCallContext - { - public: - void reset() - { - m_arg_count = 0; - m_data_count = 0; - } + class scrNativeCallContext + { + public: + constexpr void reset() + { + m_arg_count = 0; + m_data_count = 0; + } - template - void push_arg(T &&value) - { - static_assert(sizeof(T) <= sizeof(std::uint64_t)); - *reinterpret_cast>*>(reinterpret_cast(m_args) + (m_arg_count++)) = std::forward(value); - } + template + constexpr void push_arg(T&& value) + { + static_assert(sizeof(T) <= sizeof(std::uint64_t)); + *reinterpret_cast>*>(reinterpret_cast(m_args) + (m_arg_count++)) = std::forward(value); + } - template - T &get_arg(std::size_t index) - { - static_assert(sizeof(T) <= sizeof(std::uint64_t)); - return *reinterpret_cast(reinterpret_cast(m_args) + index); - } + template + constexpr T& get_arg(std::size_t index) + { + static_assert(sizeof(T) <= sizeof(std::uint64_t)); + return *reinterpret_cast(reinterpret_cast(m_args) + index); + } - template - void set_arg(std::size_t index, T &&value) - { - static_assert(sizeof(T) <= sizeof(std::uint64_t)); - *reinterpret_cast>*>(reinterpret_cast(m_args) + index) = std::forward(value); - } + template + constexpr void set_arg(std::size_t index, T&& value) + { + static_assert(sizeof(T) <= sizeof(std::uint64_t)); + *reinterpret_cast>*>(reinterpret_cast(m_args) + index) = std::forward(value); + } - template - T *get_return_value() - { - return reinterpret_cast(m_return_value); - } + template + constexpr T* get_return_value() + { + return reinterpret_cast(m_return_value); + } - template - void set_return_value(T &&value) - { - *reinterpret_cast>*>(m_return_value) = std::forward(value); - } - protected: - void *m_return_value; - std::uint32_t m_arg_count; - void *m_args; - std::int32_t m_data_count; - std::uint32_t m_data[48]; - }; - static_assert(sizeof(scrNativeCallContext) == 0xE0); + template + constexpr void set_return_value(T&& value) + { + *reinterpret_cast>*>(m_return_value) = std::forward(value); + } + protected: + void* m_return_value; + std::uint32_t m_arg_count; + void* m_args; + std::int32_t m_data_count; + std::uint32_t m_data[48]; + }; + static_assert(sizeof(scrNativeCallContext) == 0xE0); - using scrNativeHash = std::int64_t; - using scrNativePair = std::pair; - using scrNativeHandler = void(*)(scrNativeCallContext*); + using scrNativeHash = std::int64_t; + using scrNativePair = std::pair; + using scrNativeHandler = void(*)(scrNativeCallContext*); } \ No newline at end of file diff --git a/vehicle/CTrainConfig.hpp b/vehicle/CTrainConfig.hpp new file mode 100644 index 0000000..f571bd8 --- /dev/null +++ b/vehicle/CTrainConfig.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "rage/atArray.hpp" + +#pragma pack(push, 4) +class CCarriageConfig +{ + uint32_t m_name_hash; // 0x00 + int m_max_peds_per_carriage; // 0x04 + char m_pad[4]; // 0x08 + bool m_flip_model_dir; // 0x0C + bool m_do_interior_lights; // 0x0D + float m_carriage_vert_offset; // 0x10 +}; +static_assert(sizeof(CCarriageConfig) == 0x14); + +class CTrainConfig +{ +public: + uint32_t m_name_hash; // 0x00 + float m_populate_train_dist; // 0x04 + int m_unk1; // 0x08 + int m_unk2; // 0x0C + int m_unk3; // 0x10 + bool m_announce_stations; // 0x14 + bool m_doors_beep; // 0x15 + bool m_carriages_hang; // 0x16 + bool m_carriages_swing; // 0x17 + bool m_no_carriage_gap; // 0x18 + bool m_link_tracks_with_adjacent_stations; // 0x19 + bool m_no_random_spawn; // 0x1A + float m_carriage_gap; // 0x1C + rage::atArray m_carraige_configs; // 0x20 +}; +static_assert(sizeof(CTrainConfig) == 0x30); +#pragma pack(pop) \ No newline at end of file