#ifndef OBJECT_SDK_HPP
#define OBJECT_SDK_HPP

#define current_class reinterpret_cast<std::uintptr_t>( this )

#define declare_member(type, name, offset) type name() { return g_vm->read<type>( current_class + offset ); } 
#define declare_member_bit(Bit, Name, Offset) bool Name( ) { return bool( g_vm->read<char>( current_class + Offset) & (1 << Bit)); }

#define apply_member(type, name, offset) void name( type val ) { g_vm->write<type>( current_class + offset, val); }
#define apply_member_bit(Bit, Name, Offset) void Name( bool Value ) { g_vm->write<char>( g_vm->read<char>( current_class + Offset) | (1 << Bit), Value); }

namespace enums
{
	enum hightlight : int32_t
	{
		yellow = 12,
		cyan = 8,
		red = 11
	};

	enum class ItemGroup
	{
		Searchables,
		Dropped,
		World,
		Vehicles,
		Marker
	};

	enum class ColorMode
	{
		Default,
		RGB,
		Pastel,
		DPastel,
		Saturated
	};

	enum class EBlendMode : uint8_t {
		BLEND_Opaque = 0,
		BLEND_Masked = 1,
		BLEND_Translucent = 2,
		BLEND_Additive = 3,
		BLEND_Modulate = 4,
		BLEND_AlphaComposite = 5,
		BLEND_AlphaHoldout = 6,
		BLEND_TranslucentColoredTransmittance = 7,
		BLEND_MAX = 8,
		BLEND_TranslucentGreyTransmittance = 2,
		BLEND_ColoredTransmittanceOnly = 4
	};

	// Enum FortniteGame.EFortRarity
	enum class fort_item_tier : uint8_t {
		Common = 0,
		Uncommon = 1,
		Rare = 2,
		Epic = 3,
		Legendary = 4,
		Mythic = 5,
		Transcendent = 6,
		Unattainable = 7,
		NumRarityValues = 8,
		EFortRarity_MAX = 9
	};

	enum EFortWeaponCoreAnimation : uint8_t
	{
		Melee = 0,
		Pistol = 1,
		Shotgun = 2,
		PaperBlueprint = 3,
		Rifle = 4,
		MeleeOneHand = 5,
		MachinePistol = 6,
		RocketLauncher = 7,
		GrenadeLauncher = 8,
		GoingCommando = 9,
		AssaultRifle = 10,
		TacticalShotgun = 11,
		SniperRifle = 12,
		TrapPlacement = 13,
		ShoulderLauncher = 14,
		AbilityDecoTool = 15,
		Crossbow = 16,
		C4 = 17,
		RemoteControl = 18,
		DualWield = 19,
		AR_BullPup = 20,
		AR_ForwardGrip = 21,
		MedPackPaddles = 22,
		SMG_P90 = 23,
		AR_DrumGun = 24,
		Consumable_Small = 25,
		Consumable_Large = 26,
		Balloon = 27,
		MountedTurret = 28,
		CreativeTool = 29,
		ExplosiveBow = 30,
		AshtonIndigo = 31,
		AshtonChicago = 32,
		MeleeDualWield = 33,
		Unarmed = 34
	};

	// Enum FortniteGame.EFortItemType
	enum class fort_item_type : std::uint8_t {
		WorldItem = 0,
		Ammo = 1,
		Badge = 2,
		BackpackPickup = 3,
		BuildingPiece = 4,
		CharacterPart = 5,
		Consumable = 6,
		Deco = 7,
		EditTool = 8,
		Ingredient = 9,
		ItemCache = 10,
		Food = 11,
		Gadget = 12,
		AthenaGadget = 13,
		HomebaseGadget = 14,
		BattleLabDevice = 15,
		SpyTechPerk = 16,
		HeroAbility = 17,
		MissionItem = 18,
		Trap = 19,
		MultiItem = 20,
		Weapon = 21,
		WeaponMelee = 22,
		WeaponRanged = 23,
		WeaponHarvest = 24,
		WeaponCreativePhone = 25,
		WeaponMod = 26,
		WorldResource = 27,
		CreativeUserPrefab = 28,
		CreativePlayset = 29,
		Vehicle = 30,
		Npc = 31,
		PlayerAugment = 32,
		AccountItem = 33,
		AccountResource = 34,
		CollectedResource = 35,
		Alteration = 36,
		CardPack = 37,
		Currency = 38,
		Hero = 39,
		Schematic = 40,
		Worker = 41,
		TeamPerk = 42,
		PlayerTech = 43,
		Token = 44,
		DailyRewardScheduleToken = 45,
		CodeToken = 46,
		Stat = 47,
		Buff = 48,
		BuffCredit = 49,
		Quest = 50,
		Accolades = 51,
		FriendChest = 52,
		MedalsPunchCard = 53,
		RepeatableDailiesCard = 54,
		ChallengeBundle = 55,
		ChallengeBundleSchedule = 56,
		ChallengeBundleCompletionToken = 57,
		GameplayModifier = 58,
		Outpost = 59,
		HomebaseNode = 60,
		Defender = 61,
		ConversionControl = 62,
		DeployableBaseCloudSave = 63,
		ConsumableAccountItem = 64,
		Quota = 65,
		Expedition = 66,
		HomebaseBannerIcon = 67,
		HomebaseBannerColor = 68,
		AthenaSkyDiveContrail = 69,
		PersonalVehicle = 70,
		AthenaGlider = 71,
		AthenaPickaxe = 72,
		AthenaHat = 73,
		AthenaBackpack = 74,
		AthenaCharacter = 75,
		AthenaDance = 76,
		AthenaConsumableEmote = 77,
		AthenaLoadingScreen = 78,
		AthenaBattleBus = 79,
		AthenaVehicleCosmetic = 80,
		AthenaItemWrap = 81,
		AthenaCallingCard = 82,
		AthenaMapMarker = 83,
		AthenaMusicPack = 84,
		AthenaPetCosmetic = 85,
		AthenaCharmCosmetic = 86,
		AthenaVictoryPose = 87,
		AthenaSeasonTreasure = 88,
		AthenaSeason = 89,
		AthenaRewardGraph = 90,
		AthenaExtResource = 91,
		EventDescription = 92,
		BattleLabDeviceAccount = 93,
		AthenaEventToken = 94,
		EventPurchaseTracker = 95,
		CosmeticVariantToken = 96,
		CampaignHeroLoadout = 97,
		Playset = 98,
		PrerollData = 99,
		CreativePlot = 100,
		PlayerSurveyToken = 101,
		CosmeticLocker = 102,
		BannerToken = 103,
		RestedXpBoosterToken = 104,
		RewardEventGraphPurchaseToken = 105,
		HardcoreModifier = 106,
		EventDependentItem = 107,
		ItemAccessToken = 108,
		STWAccoladeReward = 109,
		Campsite = 110,
		VictoryCrown = 111,
		RealitySapling = 112,
		Apparel = 113,
		ApparelLayout = 114,
		PlayerAugmentsPersistence = 115,
		SparksAura = 116,
		SparksGuitar = 117,
		SparksBass = 118,
		SparksKeyboard = 119,
		SparksMicrophone = 120,
		SparksDrums = 121,
		SparksSpotlightAnim = 122,
		SparksSong = 123,
		SpecialItem = 124,
		Emote = 125,
		Stack = 126,
		CollectionBookPage = 127,
		BGAConsumableWrapper = 128,
		GiftBox = 129,
		GiftBoxUnlock = 130,
		PlaysetProp = 131,
		RegCosmeticDef = 132,
		Profile = 133,
		Max_None = 134,
		EFortItemType_MAX = 135
	};

	// Enum FortniteGame.EFortRarity
	enum class fort_rarity : std::uint8_t {
		Common = 0,
		Uncommon = 1,
		Rare = 2,
		Epic = 3,
		Legendary = 4,
		Mythic = 5,
		Transcendent = 6,
		Unattainable = 7,
		NumRarityValues = 8,
		EFortRarity_MAX = 9
	};

	struct FRankedProgressReplicatedData
	{
		char pad_0[ 0x10 ]; // 0x00(0x10)
		int32_t Rank; // 0x10(0x04)
		char pad_14[ 0x4 ]; // 0x14(0x04)
	};

	// Enum Engine.EMovementMode
	enum EMovementMode : uint8_t
	{
		MOVE_None = 0,
		MOVE_Walking = 1,
		MOVE_NavWalking = 2,
		MOVE_Falling = 3,
		MOVE_Swimming = 4,
		MOVE_Flying = 5,
		MOVE_Custom = 6,
		MOVE_MAX = 7
	};

	enum c_bones : int
	{
		head = 110,

		neck = 67,
		chest = 7,
		pelvis = 2,

		left_shoulder = 9,
		left_elbow = 10,
		left_hand = 11,

		right_shoulder = 38,
		right_elbow = 39,
		right_hand = 40,

		left_hip = 71,
		left_knee = 72,
		left_foot = 73,

		right_hip = 78,
		right_knee = 79,
		right_foot = 82,

		base = 0
	};
}

namespace game
{
	template<typename type>
	type gve( std::vector<type> vec, int index )
	{
		if ( index < vec.size( ) ) {
			return vec [ index ];
		}
		else {
			return type( );
		}
	}

	template<class T>
	class tarray
	{
	public:
		tarray( )
		{
			Data = NULL;
			Count = 0;
			Max = 0;
		};

		T get( std::uintptr_t idx )
		{
			return g_vm->read< T >(
				std::bit_cast< std::uintptr_t >( this->Data ) + ( idx * sizeof( T ) )
			);
		}

		std::vector<T> get_itter( )
		{
			if ( !this->is_valid( ) )
			{
				return std::vector<T>( );
			}

			if ( this->Max > 4096 ) //4096
			{
				return std::vector<T>( );
			}

			size_t buffer_size = sizeof( T ) * this->Count;

			std::vector<T> buffer( this->Max );

			g_vm->read_physical( ( uintptr_t ) this->Data, buffer.data( ), buffer_size );

			buffer.resize( this->Count );

			return buffer;
		}

		std::uintptr_t get_addr( )
		{
			return reinterpret_cast< std::uintptr_t >( this->Data );
		}

		std::uint32_t size( ) const
		{
			return this->Count;
		};

		std::uint32_t max_size( ) const
		{
			return this->Max;
		};

		bool is_valid_index( std::int32_t index ) const
		{
			return index >= 0 && index < Count;
		};

		bool is_valid( ) const
		{
			if ( Count > Max )
				return false;
			if ( !Data )
				return false;
			return true;
		}

		T* Data;
		unsigned int Count;
		unsigned int Max;
	};

	struct fbox_sphere_bounds final
	{
	public:
		struct math::vector3                        orgin;                                            // 0x0000(0x0018)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
		struct math::vector3                        box_extent;                                         // 0x0018(0x0018)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
		double                                      sphere_radius;                                      // 0x0030(0x0008)(Edit, BlueprintVisible, ZeroConstructor, SaveGame, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
	};

	class FName
	{
	public:
		int32_t ComparisonIndex;

		std::string ToString() const
		{
			return ToString( ComparisonIndex );
		}

		static std::string ToString( int32_t index )
		{
			int32_t DecryptedIndex = DecryptIndex( index );
			uint64_t NamePoolChunk = g_vm->read<uint64_t>( g_vm->image_base + 0x17358300 + 8 * ( HIWORD( DecryptedIndex ) + 2 ) ) + 2 * ( uint16_t ) DecryptedIndex;

			if ( !memory::is_valid( NamePoolChunk ) )
				return hash_str( "None" );
			
			uint16_t Pool = g_vm->read<uint16_t>( NamePoolChunk );

			if ( ( ( Pool ^ 0xD ) & 0x3FF ) == 0 )
			{
				DecryptedIndex = DecryptIndex( g_vm->read<int32_t>( NamePoolChunk + 2 ) );
				NamePoolChunk = g_vm->read<uint64_t>( g_vm->image_base + 0x17358300 + 8 * ( HIWORD( DecryptedIndex ) + 2 ) ) + 2 * ( uint16_t ) DecryptedIndex;
				if ( !memory::is_valid( NamePoolChunk ) )
					return hash_str( "None" );
				
				Pool = g_vm->read<uint16_t>( NamePoolChunk );
			}

			int32_t Length = ( ( Pool ^ 0xD ) & 0x3FF ) * ( ( ( Pool & 0x8000u ) != 0 ) ? 2 : 1 );

			std::string NameBuffer( Length, '\0' );
			g_vm->read_physical( NamePoolChunk + 2, &NameBuffer[ 0 ], Length );
			DecryptFName( &NameBuffer[ 0 ], Length );
			return NameBuffer;
		}

		static int32_t DecryptIndex( int32_t index )
		{
			if ( index )
			{
				int32_t DecryptedIndex = ( ( index - 1 ) ^ 0xB97E0A91 ) + 1;
				return DecryptedIndex ? DecryptedIndex : 1182922095;
			}
			return 0;
		}

		static void DecryptFName( char* buffer, int length )
		{
			if ( length )
			{
				int naan = 0x1358109 + 8252 * length;

				for ( int indra = 0; indra < length; ++indra )
				{
					buffer[ indra ] = buffer[ indra ] ^ ( naan - 12 );
					naan = 0x1358109 + 8252 * naan;
				}
			}

			buffer[ length ] = '\0';
		}
	};

	template<typename t>
	inline auto valid_pointer( t pointer ) -> bool {
		return ( pointer && pointer > ( t ) 0x400000 && pointer < ( t ) 0x7FFFFFFFFFFF );
	}

	// Class CoreUObject.Object
	class u_object
	{
	public:
		inline auto get_current_class( ) {
			return current_class;
		}

		inline auto is_valid( ) -> bool
		{
			auto ptr = reinterpret_cast< __int64 >( this );

			if ( ( ptr < 0xFFFFFFFFFF ) || ( ptr > 0x2FFFFFFFFFF ) )
				return false;

			if ( !memory::is_valid( ptr ) )
				return false;

			return true;
		}

	public:
		declare_member( FName, name_private, 0xC );
	};

	// Class FortniteGame.USceneComponent
	class u_scene_component : public u_object
	{
	public:
		// FortniteGame.USceneComponent::RelativeLocation
		declare_member( math::vector3, relative_location, 0x138 );

		// FortniteGame.USceneComponent::RelativeRotation
		declare_member( math::vector3, relative_rotation, 0x150 );

		// FortniteGame.USceneComponent::ComponentVelocity
		declare_member( math::vector3, component_velocity, 0x180 );

		// FortniteGame.USceneComponent::ComponentVelocity
		apply_member( math::vector3, set_component_velocity, 0x180 );

		// FortniteGame.USceneComponent::RelativeTransform
		declare_member( math::vector3, get_relative_transform, 0x200 );

		// FortniteGame.USceneComponent::RelativeTransform
		apply_member( math::vector3, set_relative_transform, 0x200 );
	};

	// Class FortniteGame.UPrimitiveComponent
	class u_primitive_component : public u_scene_component
	{
	public:
		// FortniteGame.UPrimitiveComponent::BoundsScale + 0x1C
		declare_member( float, last_render_time_on_screen, 0x32c );

		apply_member_bit( 6, bRenderCustomDepth, 0x271 );
	};

	class u_mesh_component : public u_primitive_component
	{
	public:
	};

	// Class FortniteGame.USkinnedMeshComponent
	class u_skinned_mesh_component : public u_mesh_component
	{
	public:
		declare_member( std::int32_t, is_cached, 0x5D8 );
		//declare_member( tarray<engine::transform>, bone_array, 0x5A8 + ( this->is_cached( ) * 0x10 ) );

		auto bone_array( ) -> tarray<engine::transform>
		{
			auto mesh = get_current_class( );

			if ( !memory::is_valid( mesh ) )
				return {};

			auto bone_array = g_vm->read<std::uint64_t>( mesh + 0x5C8 );

			if ( memory::is_valid( bone_array ) )
				return g_vm->read<tarray<engine::transform>>( mesh + 0x5C8 );
			else if ( !memory::is_valid( bone_array ) )
				return g_vm->read<tarray<engine::transform>>( mesh + 0x5C8 + 0x10 );
		}

		declare_member( engine::transform, component_to_world, 0x1E0 );

	public:
		auto get_bone_location( engine::transform bone_transform ) -> math::vector3
		{
			auto matrix = bone_transform.to_matrix( ).to_multiplication(
				this->component_to_world( ).to_matrix( )
			);

			return matrix.w_plane;
		}

		auto get_bone_map( const std::vector<std::pair<std::uint32_t, std::uint32_t>>& bone_pairs, std::vector<engine::transform> bone_transform, engine::transform ctw ) -> std::unordered_map<int, math::vector3>
		{
			std::unordered_map<int, math::vector3> bone_positions;

			for ( const auto& pair : bone_pairs )
			{
				std::vector<std::uint32_t> bones_to_process = { pair.first, pair.second };

				for ( auto index : bones_to_process )
				{
					if ( bone_positions.find( index ) == bone_positions.end( ) )
					{
						auto matrix = bone_transform [ index ].to_matrix( ).to_multiplication(
							ctw.to_matrix( )
						);

						bone_positions [ index ] = math::vector3( matrix.w_plane.x, matrix.w_plane.y, matrix.w_plane.z );
					}
				}
			}

			return bone_positions;
		}
	};

	// Class FortniteGame.SkeletalMeshComponent
	class u_skeletal_mesh_component : public u_skinned_mesh_component
	{
	public:
		declare_member( fbox_sphere_bounds, get_bounds, 0x100 );

		auto get_player_dimensions( bounds::bounds_t* out_bounds ) -> bool
		{
			const auto get_bounds = [ & ] ( bounds::bounds_t& out, float expand = 0.f ) -> bool
			{
				bounds::bounds_t bounds = { flt_max, flt_min, flt_max, flt_min };

				for ( auto& bone : bounds::bone_itter )
				{
					auto bone_pos = g_engine->get_bone( this->get_current_class(), bone.index );

					switch ( bone.index )
					{
						case 110:
						{
							bone_pos.z += 15;
							break;
						}
					}

					bone.screen = g_engine->world_to_screen( bone_pos );

					if ( bone.screen.x < bounds.left )
						bounds.left = bone.screen.x;
					else if ( bone.screen.x > bounds.right )
						bounds.right = bone.screen.x;
					if ( bone.screen.y < bounds.top )
						bounds.top = bone.screen.y;
					else if ( bone.screen.y > bounds.bottom )
						bounds.bottom = bone.screen.y;
				}

				if ( bounds.left == flt_max )
					return false;
				if ( bounds.right == flt_min )
					return false;
				if ( bounds.top == flt_max )
					return false;
				if ( bounds.bottom == flt_min )
					return false;

				bounds.left += -expand;
				bounds.right += expand;
				bounds.top += -expand;
				bounds.bottom += expand;

				out = bounds;

				return true;
			};

			bounds::bounds_t bounds{};
			if ( get_bounds( bounds, 9.f ) )
			{
				*out_bounds = bounds;
				return true;
			}

			return false;

		}

	public:
		auto is_visible( const std::uintptr_t& u_world ) -> bool
		{
			// FortniteGame.UWorld::WorldTimeSeconds
			return ( g_vm->read<double>( u_world + 0x160 ) ) - last_render_time_on_screen() <= 0.06f;
		}
	};

	// Class FortniteGame.AActor
	class a_actor : public u_object
	{
	public:

		// FortniteGame.AFortProjectileAthena::FireStartLoc
		apply_member( math::vector3, set_FireStartLoc, 0xc50 );

		// FortniteGame.AActor::RootComponent
		declare_member( u_scene_component*, root_component, 0x1b0 );
	};

	// Class Engine.FTextData
	class f_text_data
	{
	public:
		auto get() -> std::string
		{
			const auto& __ftext = current_class;

			if ( memory::is_valid( __ftext ) )
			{
				const auto& src = g_vm->read<std::uint64_t>( __ftext + 0x20 );

				if ( memory::is_valid( src ) )
				{
					const auto& size = g_vm->read<std::int32_t>( __ftext + 0x28 );

					if ( size > 0 && size < 100 )
					{
						std::unique_ptr<wchar_t[ ]> dst( new ( std::nothrow ) wchar_t[ size ] );

						g_vm->read_physical(
							src,
							dst.get(),
							size * sizeof( wchar_t )
						);


						std::wstring conversion( dst.get() );

						return std::string( conversion.begin(), conversion.end() );
					}
				}
			}

			return hash_str( "NULL" );
		}
	};

	// Class FortniteGame.Controller
	struct a_controller : public a_actor
	{
	public:
	};

	// Class FortniteGame.UFortItemDefinition
	struct u_fort_item_definition : public a_actor
	{
		// FortniteGame.UFortItemDefinition::Rarity
		declare_member( enums::fort_rarity, tier, 0xa2 );

		// FortniteGame.UItemDefinitionBase::ItemName
		declare_member( f_text_data*, display_name, 0x40 );
	};

	struct u_fort_world_item_definition : public u_fort_item_definition
	{
	public:
	};

	// Class Engine.DataTable
	struct data_table : public u_object
	{
	public:

	};

	//// Class Engine.DataTableRowHandle
	//struct data_table_row_handle : public u_object
	//{
	//public:
	//	declare_member( data_table*, DataTable, 0x0 );
	//	declare_member( FName, RowName, 0x8 );
	//};

	// Class FortniteGame.UFortWeaponItemDefinition
	struct u_fort_weapon_item_defintion : public u_fort_world_item_definition
	{
	public:
	};

	struct FFortWeaponRampingData
	{
	public:
		bool bIsRampingWeapon; // 0x0 (Size: 0x1)
		float MaxRampStacks; // 0x8 (Size: 0x28)
		float RampFireRateToAdd; // 0x30 (Size: 0x28)
		float RampGraceDuration; // 0x58 (Size: 0x28)
	};

	// Class FortniteGame.UFortWeaponOpticDefinition
	class u_fort_weapon_optic_definition : public u_object
	{
	public:
		// FortniteGame.UFortWeaponOpticDefinition::FieldOfView
		apply_member( float, set_FieldOfView, 0xf8 );
	};

	// Class FortniteGame.AFortWeapon
	struct a_fort_weapon : public a_actor
	{
	public:
		// FortniteGame.AFortWeapon::WeaponData
		declare_member( u_fort_weapon_item_defintion*, weapon_data, 0x570 );

		// FortniteGame.AFortWeapon::OpticDefinition
		declare_member( u_fort_weapon_optic_definition*, optic_definition, 0x1070 );

		// FortniteGame.AFortWeapon::WeaponCoreAnimation
		declare_member( enums::EFortWeaponCoreAnimation, core_animation_type, 0x1488 );

		// FortniteGame.AFortWeapon::AmmoCount
		declare_member( std::int32_t, ammo_count, 0xefc );

		// FortniteGame.AFortWeapon::bIsReloadingWeapon
		declare_member_bit( 0, reloading, 0x3b1 );

		// FortniteGame.AFortWeapon::RampingFireRateData
		apply_member( FFortWeaponRampingData, set_FFortWeaponRampingData, 0x1e00 );

		// Engine.AFortWeapon
		declare_member( float, bullet_speed, 0x1ad0 ); // 0x1ad0, 0x1d00, 0x1e64

		// Engine.AFortWeapon
		declare_member( float, bullet_gravity, 0x1e68 );

		// FortniteGame.AFortWeaponRanged.bUseAthenaRecoil
		apply_member( bool, set_bUseAthenaRecoil, 0x2012 );

		// FortniteGame.AFortWeaponRanged.bEnableRecoilDelay
		apply_member( bool, set_bEnableRecoilDelay, 0x20d4 );

		// FortniteGame.AFortWeaponRanged.BulletCountForPerBulletRecoil
		apply_member( float, set_BulletCountForPerBulletRecoil, 0x2018 );

		// FortniteGame.AFortWeaponRanged.FirstShotAccuracyMinWaitTime
		apply_member( float, set_FirstShotAccuracyMinWaitTime, 0x2014 );

		// FortniteGame.AFortWeaponRanged.BulletCountForPerBulletSpread
		apply_member( float, set_BulletCountForPerBulletSpread, 0x201c );

		// FortniteGame.AFortWeaponRanged.TimeRemainingForBulletSpread
		apply_member( float, set_TimeRemainingForBulletSpread, 0x2020 );

		// FortniteGame.AFortWeaponRanged.bUseAthenaRecoil
		declare_member( bool, get_bUseAthenaRecoil, 0x2012 );

		// FortniteGame.AFortWeaponRanged.bEnableRecoilDelay
		declare_member( bool, get_bEnableRecoilDelay, 0x20d4 );

		// FortniteGame.AFortWeaponRanged.BulletCountForPerBulletRecoil
		declare_member( float, get_BulletCountForPerBulletRecoil, 0x2018 );

		// FortniteGame.AFortWeaponRanged.FirstShotAccuracyMinWaitTime
		declare_member( float, get_FirstShotAccuracyMinWaitTime, 0x2014 );

		// FortniteGame.AFortWeaponRanged.BulletCountForPerBulletSpread
		declare_member( float, get_BulletCountForPerBulletSpread, 0x201c );

		// FortniteGame.AFortWeaponRanged.TimeRemainingForBulletSpread
		declare_member( float, get_TimeRemainingForBulletSpread, 0x2020 );
	};

	// Class FortniteGame.AFortPawn
	class a_pawn : public a_actor
	{
	public:

		// FortniteGame.AFortPickup::PrimaryPickupItemEntry
		declare_member( u_fort_item_definition*, pickup_entry, 0x370 + 0x10 );
	};

	struct u_static_mesh : public u_object
	{
	public:
		auto expand_transform( math::vector3 scale ) -> void
		{
			auto default_packet = g_vm->read<std::uint64_t>(
				current_class + 0x508
			);

			if ( default_packet )
			{
				auto ref_bone_scale = g_vm->read<std::uint64_t>(
					default_packet + 0x338
				);

				g_vm->write<math::vector3>( ref_bone_scale + 0x1E0 + 0x40, scale );
			}
		}
	};

	// Class FortniteGame.UCharacterMovementComponent
	struct u_character_movement_component : public u_object
	{
	public:
		// FortniteGame.UCharacterMovementComponent::LastUpdateRequestedVelocity
		declare_member( math::vector3, last_update_velocity, 0x590 );

		// FortniteGame.UCharacterMovementComponent::LastUpdateLocation
		declare_member( math::vector3, last_update_location, 0x360 );

		// FortniteGame.UCharacterMovementComponent::LastUpdateRotation
		declare_member( math::vector3, last_update_rotation, 0x340 );

		// FortniteGame.UCharacterMovementComponent::MovementMode
		declare_member( enums::EMovementMode, movement_mode, 0x231 );
	};

	// Class FortniteGame.ACharacter
	class a_character : public a_pawn
	{
	public:
		// FortniteGame.ACharacter::Mesh
		declare_member( u_skeletal_mesh_component*, mesh, 0x328 );

		// FortniteGame.ACharacter::CharacterMovement
		declare_member( u_character_movement_component*, character_movement, 0x330 );

		// FortniteGame.ACharacter::bIsCrouched
		declare_member_bit( 1, bIsCrouched, 0x440 );
	};

	struct afgf_character : public a_character
	{
	public:
	};


	// Class FortniteGame.AFortPawn
	struct a_fort_pawn : public afgf_character
	{
	public:

		// FortniteGame.AFortPawn::CurrentWeapon
		declare_member( a_fort_weapon*, current_weapon, 0xa80 );

		// FortniteGame.APawn::PlayeState
		declare_member( std::uintptr_t, player_state, 0x2c8 );

		// FortniteGame.AFortPawn::bIsDying
		declare_member_bit( 5, is_dying, 0x720 );

		// FortniteGame.AFortPawn::bIsDBNO
		declare_member_bit( 6, is_dbno, 0x962 );
	};


	struct f_replicated_athena_vehicle_attributes
	{
	public:
	};

	// Class FortniteGame.UFortMotorcycleVehicleConfigs
	struct a_fort_motorcycle_vehicle : public a_fort_pawn
	{
	public:
		// FortniteGame.UFortMotorcycleVehicleConfigs::MaxChargeJumpForce
		apply_member( float, max_charge_jump_force, 0xa30 );

		// FortniteGame.UFortMotorcycleVehicleConfigs::MaxJumpForwardAngle
		apply_member( float, max_jump_forward_angle, 0xa38 );

		// FortniteGame.UFortMotorcycleVehicleConfigs::MaxJumpChargeTime
		apply_member( float, max_jump_charge_time, 0xa28 );

		// FortniteGame.UFortMotorcycleVehicleConfigs::JumpChargeGraceTimeSeconds
		apply_member( float, jump_charge_grace_time_seconds, 0xa70 );

		// FortniteGame.UFortMotorcycleVehicleConfigs::JumpGraceTimeSeconds
		apply_member( float, jump_grace_time_seconds, 0xa74 );
	};

	// Class FortniteGame.UFortPhysicsVehicleConfigs
	struct a_fort_physics_vehicle : public a_fort_pawn
	{
	public:
		// FortniteGame.UFortVehicleConfigs::VehicleGravity
		apply_member( float, vehicle_gravity, 0xd4 );

		// FortniteGame.UFortPhysicsVehicleConfigs::DragCoefficient2
		apply_member( float, drag_coeffient, 0x4c0 );

		// FortniteGame.UFortPhysicsVehicleConfigs::HoldToExitTime    
		apply_member( float, exit_vehicle_cooldown, 0x110 );

	public:
		/*
					Vehicular					   .__                       __          
				  ____ ___  _________   ___________|__| _____   ____   _____/  |_  ______
				_/ __ \\  \/  /\____ \_/ __ \_  __ \  |/     \_/ __ \ /    \   __\/  ___/
				\  ___/ >    < |  |_> >  ___/|  | \/  |  Y Y  \  ___/|   |  \  |  \___ \ 
				 \___  >__/\_ \|   __/ \___  >__|  |__|__|_|  /\___  >___|  /__| /____  >
					 \/      \/|__|        \/               \/     \/     \/          \/ 
												- FortniteGame-33.11-CL-38773622

		*/

		// FortniteGame.UFortPhysicsVehicleConfigs::bIsVehicleKinematic
		apply_member( bool, bIsVehicleKinematic, 0x678 );

		// FortniteGame.UFortPhysicsVehicleConfigs::VehicleFlipCooldown
		apply_member( bool, VehicleFlipCooldown, 0x430 );

		// FortniteGame.UFortPhysicsVehicleConfigs::TimeBetweenShallowWaterLevelUpdates
		apply_member( bool, TimeBetweenShallowWaterLevelUpdates, 0x33c );

	public:
		auto teleport_to( math::vector3 position, u_scene_component* root_component, bool larp ) -> void
		{
			this->bIsVehicleKinematic( true );

			std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );

			root_component->set_relative_transform(
				larp ? math::vector3( position.x, position.y, position.z - 30.0 ) : position
			);

			std::this_thread::sleep_for( std::chrono::milliseconds( 150 ) );

			this->bIsVehicleKinematic( false );
		}
	};

	// Class FortniteGame.UFortVehicleFuelComponent
	struct a_fort_vehicle_fuel_component : public a_fort_pawn
	{
	public:
		// FortniteGame.UFortVehicleFuelComponent::ServerFuel
		apply_member( float, server_fuel, 0x128 );

		// FortniteGame.UFortVehicleFuelComponent::InfiniteFuel
		apply_member( float, infinite_fuel, 0x298 );
	};

	// Class FortniteGame.AFortAthenaVehicle
	struct a_fort_vehicle : public a_fort_pawn
	{
	public:
		// FortniteGame.AFortAthenaVehicle::SeatSwitchCooldown
		apply_member( float, seat_cooldown, 0xddc );

		// MotorcycleRuntime.AFortMotorcycleVehicle::FortMotorcycleVehicleConfigs
		declare_member( a_fort_motorcycle_vehicle*, motorcycle_vehicle_config, 0x2328 );

		// FortniteGame.AFortAthenaVehicle::FortPhysicsVehicleConfigs
		declare_member( a_fort_physics_vehicle*, fort_physics_vehicle_config, 0x1c80 );

		// FortniteGame.AFortAthenaVehicle::CachedFuelComponent
		declare_member( a_fort_vehicle_fuel_component*, cached_fuel_component, 0x1388 );

	};

	struct a_fort_athena_vehicle : public a_fort_vehicle
	{
	public:

		/*struct FReplicatedAthenaVehicleAttributes
		{
		public:
			float FrontLateralFrictionScale; // 0x0 (Size: 0x4)
			float RearLateralFrictionScale; // 0x4 (Size: 0x4)
			float BrakeForceTractionScale; // 0x8 (Size: 0x4)
			float ForwardForceTractionScale; // 0xc (Size: 0x4)
			float SlopeAntigravityScale; // 0x10 (Size: 0x4)
			float TopSpeedScale; // 0x14 (Size: 0x4)
			float VehicleGravityScale; // 0x18 (Size: 0x4)
			uint8_t bBrakeBeforeReverse; // 0x1c (Size: 0x1, Bit: 0)
		};*/

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.VehicleGravityScale
		apply_member( float, set_VehicleGravityScale, 0x1360 + 0x18 );

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.ForwardForceTractionScale
		apply_member( float, set_ForwardForceTractionScale, 0x1360 + 0xc );

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.TopSpeedScale
		apply_member( float, set_TopSpeedScale, 0x1360 + 0x14 );

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.BrakeForceTractionScale
		apply_member( float, set_BrakeForceTractionScale, 0x1360 + 0x8 );

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.FrontLateralFrictionScale
		apply_member( float, set_FrontLateralFrictionScale, 0x1360 + 0x0 );

		// FortniteGame.AFortAthenaVehicle::VehicleAttributes.RearLateralFrictionScale
		apply_member( float, set_RearLateralFrictionScale, 0x1360 + 0x4 );
	};

	// Class Engine.Material
	struct u_material : public u_object
	{
	public:
		apply_member( enums::EBlendMode, BlendMode, 0x141 );
		apply_member_bit( 0, bDisableDepthTest, 0x1c8 );
		apply_member_bit( 4, AllowTranslucentCustomDepthWrites, 0x1d8 );
		apply_member_bit( 0, bIsBlendable, 0x1fc );

		//auto disable_depth_test( ) -> void
		//{
		//	if ( !memory::is_valid( current_class ) ) return;

		//	char bDisableDepthTest = g_vm->read<char>( current_class + 0x1b0 );
		//	bDisableDepthTest |= ( 1 << 0 );

		//	g_vm->write<char>( current_class + 0x1b0, bDisableDepthTest );
		//}

		//auto enable_wireframe( ) -> void
		//{
		//	if ( !memory::is_valid( current_class ) ) return;

		//	char Wireframe = g_vm->read<char>( current_class + 0x1c0 );
		//	Wireframe |= ( 1 << 6 );
		//	g_vm->write<char>( current_class + 0x1c0, Wireframe );
		//}
	};

	struct u_material_instance : public u_object
	{
	public:

		auto get_material( ) -> u_material*
		{
			auto parent_one = g_vm->read<uintptr_t>( current_class + 0x128 );
			if ( !memory::is_valid( parent_one ) ) return nullptr;

			auto parent_two = g_vm->read<uintptr_t>( parent_one + 0x128 );
			if ( !memory::is_valid( parent_two ) ) return nullptr;
	
			auto parent_third = g_vm->read<uintptr_t>( parent_two + 0x128 );
			if ( !memory::is_valid( parent_third ) ) return nullptr;

			return reinterpret_cast< u_material* >( parent_third );
		}
	};

	struct a_fort_player_pawn : public a_fort_pawn
	{
	public:

		// PlayerPawn_Athena_Generic_Parent.FPlayerPawn_Athena_Generic_Parent_C::PawnMaterials_ALL
		declare_member( tarray<u_material_instance*>, pawn_materials, 0x6080 );
	};

	// Class AnimationBudgetAllocator.SkeletalMeshComponentBudgeted
	struct u_skeletal_mesh_component_budgeted : u_skinned_mesh_component
	{
	public:
		u_skeletal_mesh_component_budgeted* component [ 7 ];

		declare_member( int, get_vis_context, 0x2a0 );
		declare_member( int, get_highlight_context, 0x2a4 );

	public:
		//apply_member( int, set_highlight_context, 0x2a4 );
		//apply_member_bit( 6, bRenderCustomDepth, 0x271 );

		//// The next bit after Engine.ActorComponent.bReplicates
		//apply_member_bit( 3, bRenderStateDirty, 0x8c );

		auto set_highlight_context( int color ) -> void
		{
			if ( !memory::is_valid( current_class ) ) return;

			auto current_color = g_vm->read<int>( current_class + 0x2a4 );
			if ( current_color == color ) return; // Prevent redundant writes

			g_vm->write<int>( current_class + 0x2a4, color );
		}

		auto set_field_depth( bool enable ) -> void
		{
			if ( !memory::is_valid( current_class ) ) return;

			auto field_depth = g_vm->read<BYTE>( current_class + 0x271 );
			BYTE new_depth = enable ? ( field_depth | ( 1 << 6 ) ) : ( field_depth & ~( 1 << 6 ) );

			if ( field_depth == new_depth ) return; // Prevent redundant writes

			g_vm->write<BYTE>( current_class + 0x271, new_depth );
		}

		auto set_replication( bool enable ) -> void
		{
			if ( !memory::is_valid( current_class ) ) return;

			auto replication = g_vm->read<BYTE>( current_class + 0x8c );
			BYTE new_replication = enable ? ( replication | ( 1 << 3 ) ) : ( replication & ~( 1 << 3 ) );

			if ( replication == new_replication ) return; // Prevent redundant writes

			g_vm->write<BYTE>( current_class + 0x8c, new_replication );
		}


	public:

		auto get_material( const std::uint32_t& selected ) -> enums::hightlight {
			switch ( selected )
			{
			case 0:
				return enums::hightlight::red;
				break;
			case 1:
				return enums::hightlight::yellow;
				break;
			case 2:
				return enums::hightlight::cyan;
				break;
			default:
				return enums::hightlight::red;
				break;
			}
		}
	};

	// Class FortniteGame.AFortPlayerPawn
	struct a_fort_player_pawn_athena : public a_fort_player_pawn
	{
	public:

		// FortniteGame.AFortPlayerPawn::LastFiredDirection
		declare_member( math::vector3, get_LastFiredDirection, 0x5a60 );

		// FortniteGame.AFortPlayerPawnAthena::CurrentVehicle
		declare_member( a_fort_athena_vehicle*, current_vehicle, 0x2b78 );

		// FortniteGame.FortPlayerPawn::CharacterPartSkeletalMeshComponents
		declare_member( u_skeletal_mesh_component_budgeted, character_part_skeletal_mesh_components, 0x3118 );
	};

	struct a_weapon_correction_rotator
	{
		double pitch, yaw;
	};

	// Class FortniteGame.APlayerController
	struct a_player_controller : public a_controller
	{
	public:

		// FortniteGame.AFortPlayerController::FOVMinimum
		apply_member( float, fov_min, 0x2898 );

		// FortniteGame.AFortPlayerController::FOVMaximum
		apply_member( float, fov_max, 0x289c );

		// FortniteGame.APlayerController::AcknowledgedPawn
		declare_member( a_fort_player_pawn_athena*, acknowledged_pawn, 0x350 );

		// FortniteGame.APlayerController::LocationUnderReticle
		declare_member( math::vector3, rectile, 0x27e0 );

		// FortniteGame.APlayerController::NetConnection + Size
		apply_member( math::vector3, view_angles, 0x520 + 0x8 );

		// FortniteGame.APlayerController::NetConnection + Size
		declare_member( math::vector3, get_view_angles, 0x520 + 0x8 );

		// FortniteGame.APlayerController::OnInputFiltered + Size
		apply_member( math::vector3, rotation_reset, 0x978 + 0x10 );

		// FortniteGame.AFortPlayerController::WeaponOffsetCorrection
		apply_member( a_weapon_correction_rotator, weapon_offset_correction, 0x2960 );
	};

	// Class FortniteGame.APlayerState
	class a_player_state : public u_object
	{
	public:
		// FortniteGame.APlayerState::PawnPrivate
		declare_member( a_fort_player_pawn_athena*, pawn_private, 0x320 );

		// FortniteGame.APlayerState::bIsABot
		declare_member_bit( 3, is_bot, 0x2b2 );

	public:
		auto decrypt_name( bool is_lobby ) -> std::string
		{
			int v25;
			char v21;
			int v22;
			__int64 v6;

			std::uint64_t src;
			int size;

			const auto& state = get_current_class();
			
			if ( memory::is_valid( state ) )
			{
				if ( is_lobby )
				{
					// FortniteGame.APlayerState::PlayerNamePrivate + 0x8
					size = g_vm->read<int>( current_class + 0x340 + 0x8 );
					if ( !size || size > 100 )
						return hash_str( "NPC" );

					// FortniteGame.APlayerState::PlayerNamePrivate
					src = g_vm->read<std::uint64_t>( current_class + 0x340 );
					if ( !memory::is_valid( src ) )
						return hash_str( "NPC" );
				}
				else
				{
					// derference decryption pointer
					const auto& __routine = g_vm->read<std::uint64_t>( current_class + 0xb08 );
					if ( !memory::is_valid( __routine ) )
						return hash_str( "NPC" );

					size = g_vm->read<int>( __routine + 0x10 );
					if ( !size || size > 100 )
						return hash_str( "NPC" );

					src = g_vm->read<std::uint64_t>( __routine + 0x8 );
					if ( !memory::is_valid( src ) )
						return hash_str( "NPC" );
				}

				if ( size > 0 && size < 100 )
				{
					std::unique_ptr<wchar_t[ ]> dst( new ( std::nothrow ) wchar_t[ size ] );

					g_vm->read_physical(
						src,
						dst.get(), 
						size * sizeof( wchar_t )
					);

					v6 = size;
					v21 = v6 - 1;
					v22 = 0;

					if ( v6 == 0 )
						v21 = 0;

					_WORD* v23 = (_WORD* )( dst.get() );

					for ( int i = v21 & 3;; *v23++ += i & 7 )
					{
						v25 = v6 - 1;

						if ( v6 == 0 )
							v25 = 0;

						if ( v22 >= v25 )
							break;

						i += 3;
						++v22;
					}

					std::wstring conversion( dst.get() );

					return std::string( conversion.begin(), conversion.end() );
				}
			}

			return hash_str( "NPC" );
		}

		auto decrypt_platform() -> std::string
		{
			const auto& state = get_current_class();

			if ( memory::is_valid( state ) )
			{
				// FortniteGame.APlayerState::Platform
				const auto& __active_platform = g_vm->read<std::uint64_t>( current_class + 0x430 );

				if ( memory::is_valid( __active_platform ) )
				{
					std::unique_ptr<wchar_t[ ]> dst( new ( std::nothrow ) wchar_t[ 32 ] );

					g_vm->read_physical(
						__active_platform,
						dst.get(),
						32 * sizeof( wchar_t )
					);

					std::wstring conversion( dst.get() );

					return std::string( conversion.begin(), conversion.end() );
				}
			}

			return hash_str( "PC" );
		}
	};

	class a_fort_player_state : public a_player_state
	{
	public:
	};

	// Class FortniteGame.FortPlayerStateZone
	class a_fort_player_state_zone : public a_fort_player_state
	{
	public:
	};

	// Class FortniteGame.UFortPlayerStateComponent_Habanero
	class a_fort_player_state_component_habanero : public a_fort_player_state_zone
	{
	public:

		// FortniteGame.UFortPlayerStateComponent_Habanero::FRankedProgressReplicatedData
		declare_member( enums::FRankedProgressReplicatedData, rank_information, 0xd0 );
	};

	// Class FortniteGame.AFortPlayerStateAthena
	class a_fort_player_state_athena : public a_fort_player_state_zone
	{
	public:
		// FortniteGame.AFortPlayerState::HabaneroComponent
		declare_member( a_fort_player_state_component_habanero*, habanero_component, 0xa48 );

		// FortniteGame.AFortPlayerStateAthena::KillScore
		declare_member( std::int32_t, kill_score, 0x1270 );

		// FortniteGame.AFortPlayerStateAthena::TeamIndex
		declare_member( std::uint32_t, team_id, 0x1259 );

		// FortniteGame.AFortPlayerStateZone::Spectators + SpectatorPlayerState
		declare_member( tarray< a_fort_player_state_athena*>, spectators, 0xb88 + 0x108 );
	};

	// Redacted in SDK, must be accessed directly in memory.
	struct u_scene_view_state : public u_object
	{
	public:
		declare_member( engine::c_matrix, view_state, 0x940 );
		declare_member( double, fov, 0x740 );

		auto viewmatrix() -> void {

			auto projection = this->view_state();

			g_engine->rotation.x = engine::to_deg( std::asin( projection.z_plane.w ) );
			g_engine->rotation.y = engine::to_deg( std::atan2( projection.y_plane.w, projection.x_plane.w ) );
			g_engine->rotation.z = 0.0;

			g_engine->location.x = projection.m[ 3 ][ 0 ];
			g_engine->location.y = projection.m[ 3 ][ 1 ];
			g_engine->location.z = projection.m[ 3 ][ 2 ];

			g_engine->field_of_view = engine::to_deg( atanf( 1 / this->fov() ) * 2 );
		}
	};

	// Class FortniteGame.UGameViewportClient
	struct game_viewport_client : public u_object
	{
	public:

		// Engine.
		apply_member( BYTE, set_fog_cast, 0xB0 );

		// Engine.
		declare_member( BYTE, get_fog_cast, 0xB0 );
	};

	// Class FortniteGame.ULocalPlayer
	struct u_localplayer : public u_object
	{
	public:

		// Engine.
		declare_member( tarray<u_scene_view_state*>, view_state, 0xd0 );

		// FortniteGame.UPlayer::PlayerController
		declare_member( a_player_controller*, controller, 0x30 );

		// FortniteGame.ULocalPlayer::ViewportClient
		declare_member( game_viewport_client*, viewport, 0x78 );
	};

	struct u_world_settings : public u_object
	{
	public:
		apply_member( float, speed, 0x3dc );
	};

	// Class FortniteGame.ULevel
	struct u_level : public u_object
	{
	public:
		declare_member( tarray<a_fort_player_pawn*>, actors, 0x1A8 ); // 0x178, 0x208
		declare_member( u_world_settings*, world_settings, 0x2b8 );
	};

	// Class FortniteGame.UGameInstance
	struct u_game_instance : public u_object
	{
	public:

		// FortniteGame.UGameInstance::LocalPlayers
		declare_member( tarray<u_localplayer*>, localplayers, 0x38 );

		ALWAYS_INLINE u_localplayer* get_local( ) { return this->localplayers( ).get( 0 ); }
	};

	// Class FortniteGame.AGameStateBase
	struct a_game_state_base : public u_object
	{
	public:

		// FortniteGame.AGameStateBase::ServerWorldTimeSecondsDelta
		declare_member( float, server_world_time, 0x2e0 );

		// FortniteGame.AGameStateBase::PlayerArray
		declare_member( tarray<a_fort_player_state_athena*>, player_array, 0x2c0 );

		ALWAYS_INLINE bool is_in_lobby() { return server_world_time() ? false : true; }
	};

	// Class FortniteGame.UWorld
	struct u_world : public u_object
	{
	public:

		// FortniteGame.UWorld::GameState
		declare_member( a_game_state_base*, game_state, 0x198 );

		// FortniteGame.UWorld::OwningGameInstance
		declare_member( u_game_instance*, game_instance, 0x210 );

		// FortniteGame.UWorld::Levels
		declare_member( tarray<u_level*>, levels_array, 0x1B0 );

		// FortniteGame.UWorld::PersistentLevel
		declare_member( u_level*, persistent_level, 0x38 );

		inline auto get_world( const std::uintptr_t uworld_address ) const -> u_world* {
			return g_vm->read<u_world*>( g_vm->image_base + uworld_address );
		}
	};
}


#endif // ! guard