2022-10-19 00:30:32 +02:00
# include "gta_data_service.hpp"
2023-03-01 21:27:15 +00:00
2022-10-19 00:30:32 +02:00
# include "fiber_pool.hpp"
2023-03-01 21:27:15 +00:00
# include "file_manager.hpp"
2022-10-19 00:30:32 +02:00
# include "natives.hpp"
# include "pointers.hpp"
# include "pugixml.hpp"
# include "script.hpp"
2022-07-19 18:19:19 +08:00
# include "thread_pool.hpp"
2023-04-02 00:37:26 +08:00
# include "util/misc.hpp"
# include "util/model_info.hpp"
2023-08-29 23:22:10 +02:00
# include "util/protection.hpp"
2023-04-06 20:01:23 +02:00
# include "util/session.hpp"
# include "util/vehicle.hpp"
# include "yim_fipackfile.hpp"
2022-07-29 19:51:19 +08:00
2023-09-22 17:16:33 -04:00
# include <algorithm>
2023-08-29 23:22:10 +02:00
2022-07-19 18:19:19 +08:00
namespace big
{
2022-10-19 00:30:32 +02:00
bool add_if_not_exists ( string_vec & vec , std : : string str )
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
if ( std : : find ( vec . begin ( ) , vec . end ( ) , str ) ! = vec . end ( ) )
return true ;
vec . emplace_back ( std : : move ( str ) ) ;
return false ;
}
gta_data_service : : gta_data_service ( ) :
2023-07-08 17:54:59 +02:00
m_peds_cache ( g_file_manager . get_project_file ( " ./cache/peds.bin " ) , 5 ) ,
2023-09-22 17:16:33 -04:00
m_vehicles_cache ( g_file_manager . get_project_file ( " ./cache/vehicles.bin " ) , 6 ) ,
2023-03-01 21:27:15 +00:00
m_update_state ( eGtaDataUpdateState : : IDLE )
2022-10-19 00:30:32 +02:00
{
if ( ! is_cache_up_to_date ( ) )
m_update_state = eGtaDataUpdateState : : NEEDS_UPDATE ;
else
load_data ( ) ;
2022-07-29 19:51:19 +08:00
2022-07-19 18:19:19 +08:00
g_gta_data_service = this ;
}
gta_data_service : : ~ gta_data_service ( )
{
g_gta_data_service = nullptr ;
}
2022-10-19 00:30:32 +02:00
bool gta_data_service : : cache_needs_update ( ) const
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
return m_update_state = = eGtaDataUpdateState : : NEEDS_UPDATE ;
2022-07-19 18:19:19 +08:00
}
2022-10-19 00:30:32 +02:00
eGtaDataUpdateState gta_data_service : : state ( ) const
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
return m_update_state ;
2022-07-19 18:19:19 +08:00
}
2023-04-02 00:37:26 +08:00
void gta_data_service : : set_state ( eGtaDataUpdateState state )
{
m_update_state = state ;
}
2022-10-19 00:30:32 +02:00
void gta_data_service : : update_now ( )
{
2023-02-10 22:36:32 +01:00
m_update_state = eGtaDataUpdateState : : WAITING_FOR_SINGLE_PLAYER ;
2023-03-01 21:27:15 +00:00
g_fiber_pool - > queue_job ( [ this ] {
2023-04-02 00:37:26 +08:00
m_update_state = eGtaDataUpdateState : : UPDATING ;
rebuild_cache ( ) ;
} ) ;
}
2022-10-19 00:30:32 +02:00
// innefficient getters, don't care to fix right now
2023-07-20 22:46:32 +02:00
const ped_item & gta_data_service : : ped_by_hash ( uint32_t hash )
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
for ( const auto & [ name , ped ] : m_peds )
2023-12-05 03:58:35 -05:00
if ( ped . m_hash = = hash )
2022-10-19 00:30:32 +02:00
return ped ;
return gta_data_service : : empty_ped ;
2022-07-19 18:19:19 +08:00
}
2023-07-20 22:46:32 +02:00
const vehicle_item & gta_data_service : : vehicle_by_hash ( uint32_t hash )
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
for ( const auto & [ name , veh ] : m_vehicles )
2023-12-05 03:58:35 -05:00
if ( veh . m_hash = = hash )
2022-10-19 00:30:32 +02:00
return veh ;
return gta_data_service : : empty_vehicle ;
2022-07-19 18:19:19 +08:00
}
2023-07-20 22:46:32 +02:00
const weapon_item & gta_data_service : : weapon_by_hash ( uint32_t hash )
2022-07-29 19:51:19 +08:00
{
2023-07-07 18:52:52 -04:00
for ( const auto & [ name , weapon ] : m_weapons_cache . weapon_map )
2023-12-05 03:58:35 -05:00
if ( weapon . m_hash = = hash )
2022-10-19 00:30:32 +02:00
return weapon ;
return gta_data_service : : empty_weapon ;
2022-07-29 19:51:19 +08:00
}
2023-07-20 22:46:32 +02:00
const weapon_component & gta_data_service : : weapon_component_by_hash ( uint32_t hash )
2023-07-07 18:52:52 -04:00
{
2023-07-09 17:01:42 -04:00
for ( const auto & [ name , component ] : m_weapons_cache . weapon_components )
if ( component . m_hash = = hash )
return component ;
2023-07-07 18:52:52 -04:00
return gta_data_service : : empty_component ;
}
const weapon_component & gta_data_service : : weapon_component_by_name ( std : : string name )
{
2023-07-09 17:01:42 -04:00
for ( const auto & [ name_key , component ] : m_weapons_cache . weapon_components )
if ( name_key = = name )
return component ;
2023-07-07 18:52:52 -04:00
return gta_data_service : : empty_component ;
}
2022-10-19 00:30:32 +02:00
string_vec & gta_data_service : : ped_types ( )
2022-07-29 19:51:19 +08:00
{
2022-10-19 00:30:32 +02:00
return m_ped_types ;
2022-07-29 19:51:19 +08:00
}
2022-10-19 00:30:32 +02:00
string_vec & gta_data_service : : vehicle_classes ( )
2022-07-29 19:51:19 +08:00
{
2022-10-19 00:30:32 +02:00
return m_vehicle_classes ;
2022-07-29 19:51:19 +08:00
}
2022-10-19 00:30:32 +02:00
string_vec & gta_data_service : : weapon_types ( )
{
return m_weapon_types ;
}
2022-07-29 19:51:19 +08:00
2022-10-19 00:30:32 +02:00
bool gta_data_service : : is_cache_up_to_date ( )
{
m_peds_cache . load ( ) ;
m_vehicles_cache . load ( ) ;
2023-07-07 18:52:52 -04:00
2023-07-08 17:54:59 +02:00
auto weapons_file = g_file_manager . get_project_file ( " ./cache/weapons.json " ) ;
2023-07-07 18:52:52 -04:00
if ( weapons_file . exists ( ) )
{
std : : ifstream file ( weapons_file . get_path ( ) ) ;
file . open ( weapons_file . get_path ( ) ) ;
try
{
nlohmann : : json weapons_file_json ;
file > > weapons_file_json ;
m_weapons_cache = weapons_file_json [ " weapons_cache " ] ;
file . close ( ) ;
}
catch ( const std : : exception & exception )
{
file . close ( ) ;
LOG ( WARNING ) < < " Detected corrupt weapons: " < < exception . what ( ) ;
}
}
2022-07-19 18:19:19 +08:00
2023-04-16 18:28:49 +00:00
const auto file_version = memory : : module ( " GTA5.exe " ) . size ( ) ;
2022-07-29 19:51:19 +08:00
2023-04-16 18:28:49 +00:00
return m_peds_cache . up_to_date ( file_version ) & & m_vehicles_cache . up_to_date ( file_version ) & & m_weapons_cache . up_to_date ( file_version ) ;
2022-10-19 00:30:32 +02:00
}
2022-07-19 18:19:19 +08:00
2022-10-19 00:30:32 +02:00
void gta_data_service : : load_data ( )
{
2023-02-08 23:36:55 +01:00
LOG ( VERBOSE ) < < " Loading data from cache. " ;
2022-08-13 23:17:59 +08:00
2022-10-19 00:30:32 +02:00
load_peds ( ) ;
load_vehicles ( ) ;
2023-07-16 12:04:24 +02:00
load_weapons ( ) ;
2022-08-13 23:17:59 +08:00
2023-02-08 23:36:55 +01:00
LOG ( VERBOSE ) < < " Loaded all data from cache. " ;
2022-10-19 00:30:32 +02:00
}
2022-08-13 23:17:59 +08:00
2022-10-19 00:30:32 +02:00
void gta_data_service : : load_peds ( )
{
const auto ped_count = m_peds_cache . data_size ( ) / sizeof ( ped_item ) ;
LOG ( INFO ) < < " Loading " < < ped_count < < " peds from cache. " ;
2022-08-13 23:17:59 +08:00
2022-10-19 00:30:32 +02:00
auto cached_peds = reinterpret_cast < const ped_item * > ( m_peds_cache . data ( ) ) ;
for ( size_t i = 0 ; i < ped_count ; i + + )
2022-08-13 23:17:59 +08:00
{
2022-10-19 00:30:32 +02:00
const auto ped = cached_peds [ i ] ;
2022-08-13 23:17:59 +08:00
2022-10-19 00:30:32 +02:00
add_if_not_exists ( m_ped_types , ped . m_ped_type ) ;
2023-03-01 21:27:15 +00:00
m_peds . insert ( { ped . m_name , ped } ) ;
2022-08-13 23:17:59 +08:00
}
2022-10-19 00:30:32 +02:00
std : : sort ( m_ped_types . begin ( ) , m_ped_types . end ( ) ) ;
m_peds_cache . free ( ) ;
2022-07-19 18:19:19 +08:00
}
2022-10-19 00:30:32 +02:00
void gta_data_service : : load_vehicles ( )
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
const auto vehicle_count = m_vehicles_cache . data_size ( ) / sizeof ( vehicle_item ) ;
LOG ( INFO ) < < " Loading " < < vehicle_count < < " vehicles from cache. " ;
2022-07-19 18:19:19 +08:00
2022-10-19 00:30:32 +02:00
auto cached_vehicles = reinterpret_cast < const vehicle_item * > ( m_vehicles_cache . data ( ) ) ;
for ( size_t i = 0 ; i < vehicle_count ; i + + )
2022-07-19 18:19:19 +08:00
{
2022-10-19 00:30:32 +02:00
const auto vehicle = cached_vehicles [ i ] ;
2022-07-19 18:19:19 +08:00
2022-10-19 00:30:32 +02:00
add_if_not_exists ( m_vehicle_classes , vehicle . m_vehicle_class ) ;
2023-03-01 21:27:15 +00:00
m_vehicles . insert ( { vehicle . m_name , vehicle } ) ;
2022-10-19 00:30:32 +02:00
}
2022-08-13 17:19:18 +08:00
2022-10-19 00:30:32 +02:00
std : : sort ( m_vehicle_classes . begin ( ) , m_vehicle_classes . end ( ) ) ;
m_vehicles_cache . free ( ) ;
}
2022-08-13 17:19:18 +08:00
2023-07-16 12:04:24 +02:00
void gta_data_service : : load_weapons ( )
{
LOG ( INFO ) < < " Loading " < < m_weapons_cache . weapon_map . size ( ) < < " weapons from cache. " ;
LOG ( INFO ) < < " Loading " < < m_weapons_cache . weapon_components . size ( ) < < " weapon components from cache. " ;
for ( const auto & [ _ , weapon ] : m_weapons_cache . weapon_map )
{
add_if_not_exists ( m_weapon_types , weapon . m_weapon_type ) ;
}
std : : sort ( m_weapon_types . begin ( ) , m_weapon_types . end ( ) ) ;
}
2023-07-20 22:46:32 +02:00
inline void parse_ped ( std : : vector < ped_item > & peds , std : : vector < uint32_t > & mapped_peds , pugi : : xml_document & doc )
2023-01-22 21:57:32 +00:00
{
const auto & items = doc . select_nodes ( " /CPedModelInfo__InitDataList/InitDatas/Item " ) ;
for ( const auto & item_node : items )
{
const auto & item = item_node . node ( ) ;
2023-03-01 21:27:15 +00:00
const auto name = item . child ( " Name " ) . text ( ) . as_string ( ) ;
const auto hash = rage : : joaat ( name ) ;
2023-01-22 21:57:32 +00:00
2023-08-29 23:22:10 +02:00
if ( protection : : is_crash_ped ( hash ) )
2023-04-16 18:28:49 +00:00
continue ;
2023-01-22 21:57:32 +00:00
if ( std : : find ( mapped_peds . begin ( ) , mapped_peds . end ( ) , hash ) ! = mapped_peds . end ( ) )
continue ;
mapped_peds . emplace_back ( hash ) ;
auto ped = ped_item { } ;
std : : strncpy ( ped . m_name , name , sizeof ( ped . m_name ) ) ;
const auto ped_type = item . child ( " Pedtype " ) . text ( ) . as_string ( ) ;
std : : strncpy ( ped . m_ped_type , ped_type , sizeof ( ped . m_ped_type ) ) ;
ped . m_hash = hash ;
peds . emplace_back ( std : : move ( ped ) ) ;
}
}
2022-10-19 00:30:32 +02:00
void gta_data_service : : rebuild_cache ( )
2022-07-19 18:19:19 +08:00
{
2023-07-20 22:46:32 +02:00
using hash_array = std : : vector < uint32_t > ;
2022-10-19 00:30:32 +02:00
hash_array mapped_peds ;
hash_array mapped_vehicles ;
hash_array mapped_weapons ;
2023-07-07 18:52:52 -04:00
hash_array mapped_components ;
2022-07-19 18:19:19 +08:00
2022-10-19 00:30:32 +02:00
std : : vector < ped_item > peds ;
std : : vector < vehicle_item > vehicles ;
std : : vector < weapon_item > weapons ;
2023-07-07 18:52:52 -04:00
std : : vector < weapon_component > weapon_components ;
2022-10-19 00:30:32 +02:00
2023-07-20 22:46:32 +02:00
constexpr auto exists = [ ] ( const hash_array & arr , uint32_t val ) - > bool {
2022-10-19 00:30:32 +02:00
return std : : find ( arr . begin ( ) , arr . end ( ) , val ) ! = arr . end ( ) ;
} ;
2022-07-19 18:19:19 +08:00
2022-10-19 00:30:32 +02:00
LOG ( INFO ) < < " Rebuilding cache started... " ;
2023-07-07 05:57:38 +00:00
yim_fipackfile : : add_wrapper_call_back ( [ & ] ( yim_fipackfile & rpf_wrapper , std : : filesystem : : path path ) - > void {
2023-08-29 23:22:10 +02:00
if ( path . filename ( ) = = " vehicles.meta " )
2023-07-07 05:57:38 +00:00
{
rpf_wrapper . read_xml_file ( path , [ & exists , & vehicles , & mapped_vehicles ] ( pugi : : xml_document & doc ) {
const auto & items = doc . select_nodes ( " /CVehicleModelInfo__InitDataList/InitDatas/Item " ) ;
for ( const auto & item_node : items )
{
const auto item = item_node . node ( ) ;
2022-10-19 00:30:32 +02:00
2023-09-22 17:16:33 -04:00
std : : string name = item . child ( " modelName " ) . text ( ) . as_string ( ) ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , : : toupper ) ;
2023-07-07 05:57:38 +00:00
const auto hash = rage : : joaat ( name ) ;
2023-08-29 23:22:10 +02:00
if ( protection : : is_crash_vehicle ( hash ) )
continue ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
if ( exists ( mapped_vehicles , hash ) )
continue ;
mapped_vehicles . emplace_back ( hash ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
auto veh = vehicle_item { } ;
2023-09-22 17:16:33 -04:00
std : : strncpy ( veh . m_name , name . c_str ( ) , sizeof ( veh . m_name ) ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
const auto manufacturer_display = item . child ( " vehicleMakeName " ) . text ( ) . as_string ( ) ;
std : : strncpy ( veh . m_display_manufacturer , manufacturer_display , sizeof ( veh . m_display_manufacturer ) ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
const auto game_name = item . child ( " gameName " ) . text ( ) . as_string ( ) ;
std : : strncpy ( veh . m_display_name , game_name , sizeof ( veh . m_display_name ) ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
const auto vehicle_class = item . child ( " vehicleClass " ) . text ( ) . as_string ( ) ;
constexpr auto enum_prefix_len = 3 ;
if ( std : : strlen ( vehicle_class ) > enum_prefix_len )
std : : strncpy ( veh . m_vehicle_class , vehicle_class + enum_prefix_len , sizeof ( veh . m_vehicle_class ) ) ;
2023-03-01 21:27:15 +00:00
2023-07-07 05:57:38 +00:00
veh . m_hash = hash ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
vehicles . emplace_back ( std : : move ( veh ) ) ;
}
} ) ;
}
2023-07-07 18:52:52 -04:00
else if ( const auto file_str = path . string ( ) ; file_str . find ( " weaponcomponents " ) ! = std : : string : : npos & & path . extension ( ) = = " .meta " )
{
rpf_wrapper . read_xml_file ( path , [ & exists , & weapon_components , & mapped_components ] ( pugi : : xml_document & doc ) {
const auto & items = doc . select_nodes ( " /CWeaponComponentInfoBlob/Infos/*[self::Item[@type='CWeaponComponentInfo'] or self::Item[@type='CWeaponComponentFlashLightInfo'] or self::Item[@type='CWeaponComponentScopeInfo'] or self::Item[@type='CWeaponComponentSuppressorInfo'] or self::Item[@type='CWeaponComponentVariantModelInfo'] or self::Item[@type='CWeaponComponentClipInfo']] " ) ;
for ( const auto & item_node : items )
{
const auto item = item_node . node ( ) ;
const std : : string name = item . child ( " Name " ) . text ( ) . as_string ( ) ;
const auto hash = rage : : joaat ( name ) ;
if ( ! name . starts_with ( " COMPONENT " ) )
{
continue ;
}
if ( exists ( mapped_components , hash ) )
{
continue ;
}
mapped_components . emplace_back ( hash ) ;
std : : string LocName = item . child ( " LocName " ) . text ( ) . as_string ( ) ;
std : : string LocDesc = item . child ( " LocDesc " ) . text ( ) . as_string ( ) ;
if ( LocName . ends_with ( " INVALID " ) | | LocName . ends_with ( " RAIL " ) )
{
continue ;
}
weapon_component component ;
component . m_name = name ;
component . m_hash = hash ;
component . m_display_name = LocName ;
component . m_display_desc = LocDesc ;
weapon_components . push_back ( component ) ;
}
} ) ;
}
2023-07-07 05:57:38 +00:00
else if ( const auto file_str = path . string ( ) ; file_str . find ( " weapon " ) ! = std : : string : : npos & & path . extension ( ) = = " .meta " )
{
rpf_wrapper . read_xml_file ( path , [ & exists , & weapons , & mapped_weapons ] ( pugi : : xml_document & doc ) {
const auto & items = doc . select_nodes ( " /CWeaponInfoBlob/Infos/Item/Infos/Item[@type='CWeaponInfo'] " ) ;
for ( const auto & item_node : items )
{
const auto item = item_node . node ( ) ;
const auto name = item . child ( " Name " ) . text ( ) . as_string ( ) ;
const auto hash = rage : : joaat ( name ) ;
2022-10-19 00:30:32 +02:00
2024-03-12 09:42:11 +01:00
if ( hash = = " WEAPON_BIRD_CRAP " _J )
2023-07-07 05:57:38 +00:00
continue ;
2023-01-22 21:57:32 +00:00
2023-07-07 05:57:38 +00:00
if ( exists ( mapped_weapons , hash ) )
continue ;
mapped_weapons . emplace_back ( hash ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
const auto human_name_hash = item . child ( " HumanNameHash " ) . text ( ) . as_string ( ) ;
if ( std : : strcmp ( human_name_hash , " WT_INVALID " ) = = 0 | | std : : strcmp ( human_name_hash , " WT_VEHMINE " ) = = 0 )
continue ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
auto weapon = weapon_item { } ;
2022-10-19 00:30:32 +02:00
2023-07-07 18:52:52 -04:00
weapon . m_name = name ;
2022-10-19 00:30:32 +02:00
2023-07-07 18:52:52 -04:00
weapon . m_display_name = human_name_hash ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
auto weapon_flags = std : : string ( item . child ( " WeaponFlags " ) . text ( ) . as_string ( ) ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
bool is_gun = false ;
bool is_rechargable = false ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
const char * category = " " ;
2023-01-22 21:57:32 +00:00
2023-07-07 05:57:38 +00:00
std : : size_t pos ;
while ( ( pos = weapon_flags . find ( ' ' ) ) ! = std : : string : : npos )
{
const auto flag = weapon_flags . substr ( 0 , pos ) ;
if ( flag = = " Thrown " )
2023-01-22 21:57:32 +00:00
{
2023-07-07 05:57:38 +00:00
weapon . m_throwable = true ;
2022-10-19 00:30:32 +02:00
}
2023-07-07 05:57:38 +00:00
else if ( flag = = " Gun " )
2022-10-19 00:30:32 +02:00
{
2023-07-07 05:57:38 +00:00
is_gun = true ;
2022-10-19 00:30:32 +02:00
}
2023-07-07 05:57:38 +00:00
else if ( flag = = " DisplayRechargeTimeHUD " )
2022-10-19 00:30:32 +02:00
{
2023-07-07 05:57:38 +00:00
is_rechargable = true ;
2022-10-19 00:30:32 +02:00
}
2023-07-07 05:57:38 +00:00
else if ( flag = = " Vehicle " | | flag = = " HiddenFromWeaponWheel " | | flag = = " NotAWeapon " )
{
goto skip ;
}
weapon_flags . erase ( 0 , pos + 1 ) ;
}
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
category = item . child ( " Group " ) . text ( ) . as_string ( ) ;
2022-10-19 00:30:32 +02:00
2023-07-07 05:57:38 +00:00
if ( std : : strlen ( category ) = = 0 | | std : : strcmp ( category , " GROUP_DIGISCANNER " ) = = 0 )
2023-01-22 21:57:32 +00:00
continue ;
2023-07-07 05:57:38 +00:00
if ( std : : strlen ( category ) > 6 )
{
2023-07-07 18:52:52 -04:00
weapon . m_weapon_type = category + 6 ;
2022-10-19 00:30:32 +02:00
}
2023-04-02 00:37:26 +08:00
2023-07-07 18:52:52 -04:00
if ( is_gun | | weapon . m_weapon_type = = " MELEE " | | weapon . m_weapon_type = = " UNARMED " )
2023-07-07 05:57:38 +00:00
{
const std : : string reward_prefix = " REWARD_ " ;
weapon . m_reward_hash = rage : : joaat ( reward_prefix + name ) ;
if ( is_gun & & ! is_rechargable )
{
std : : string weapon_id = name + 7 ;
weapon . m_reward_ammo_hash = rage : : joaat ( reward_prefix + " AMMO_ " + weapon_id ) ;
}
}
2023-07-07 18:52:52 -04:00
for ( pugi : : xml_node attach_point : item . child ( " AttachPoints " ) . children ( " Item " ) )
{
for ( pugi : : xml_node component : attach_point . child ( " Components " ) . children ( " Item " ) )
{
weapon . m_attachments . push_back ( component . child_value ( " Name " ) ) ;
}
}
2023-07-07 05:57:38 +00:00
weapon . m_hash = hash ;
2023-04-16 18:28:49 +00:00
2023-07-07 05:57:38 +00:00
weapons . emplace_back ( std : : move ( weapon ) ) ;
skip :
2023-04-02 00:37:26 +08:00
continue ;
2023-07-07 05:57:38 +00:00
}
} ) ;
}
else if ( path . filename ( ) = = " peds.meta " )
{
rpf_wrapper . read_xml_file ( path , [ & exists , & peds , & mapped_peds ] ( pugi : : xml_document & doc ) {
parse_ped ( peds , mapped_peds , doc ) ;
} ) ;
}
else if ( std : : string str = rpf_wrapper . get_name ( ) ; ( str . find ( " componentpeds " ) ! = std : : string : : npos | | str . find ( " streamedpeds " ) ! = std : : string : : npos | | str . find ( " mppatches " ) ! = std : : string : : npos | | str . find ( " cutspeds " ) ! = std : : string : : npos ) & & path . extension ( ) = = " .yft " )
{
const auto name = path . stem ( ) . string ( ) ;
const auto hash = rage : : joaat ( name ) ;
2023-04-02 00:37:26 +08:00
2023-08-29 23:22:10 +02:00
if ( protection : : is_crash_ped ( hash ) )
2023-07-07 05:57:38 +00:00
return ;
2023-04-02 00:37:26 +08:00
2023-07-07 05:57:38 +00:00
if ( std : : find ( mapped_peds . begin ( ) , mapped_peds . end ( ) , hash ) ! = mapped_peds . end ( ) )
return ;
2023-04-02 00:37:26 +08:00
2023-07-07 05:57:38 +00:00
mapped_peds . emplace_back ( hash ) ;
2023-04-02 00:37:26 +08:00
2023-07-07 05:57:38 +00:00
auto ped = ped_item { } ;
2023-04-02 00:37:26 +08:00
2023-07-07 05:57:38 +00:00
std : : strncpy ( ped . m_name , name . c_str ( ) , sizeof ( ped . m_name ) ) ;
ped . m_hash = hash ;
2022-07-29 19:51:19 +08:00
2023-07-07 05:57:38 +00:00
peds . emplace_back ( std : : move ( ped ) ) ;
}
2022-10-19 00:30:32 +02:00
} ) ;
2022-07-29 19:51:19 +08:00
2023-04-02 00:37:26 +08:00
if ( state ( ) = = eGtaDataUpdateState : : UPDATING )
{
yim_fipackfile : : for_each_fipackfile ( ) ;
2023-04-06 20:01:23 +02:00
}
2023-04-02 00:37:26 +08:00
2023-08-29 23:22:10 +02:00
static bool translate_label = false ;
2023-04-02 00:37:26 +08:00
g_fiber_pool - > queue_job ( [ & ] {
for ( auto & item : vehicles )
{
std : : strncpy ( item . m_display_manufacturer , HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( item . m_display_manufacturer ) , sizeof ( item . m_display_manufacturer ) ) ;
std : : strncpy ( item . m_display_name , HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( item . m_display_name ) , sizeof ( item . m_display_name ) ) ;
char vehicle_class [ 32 ] ;
std : : sprintf ( vehicle_class , " VEH_CLASS_%i " , VEHICLE : : GET_VEHICLE_CLASS_FROM_NAME ( item . m_hash ) ) ;
std : : strncpy ( item . m_vehicle_class , HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( vehicle_class ) , sizeof ( item . m_vehicle_class ) ) ;
}
for ( auto & item : weapons )
{
2023-07-07 18:52:52 -04:00
item . m_display_name = HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( item . m_display_name . c_str ( ) ) ;
}
for ( auto & item : weapon_components )
{
item . m_display_name = HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( item . m_display_name . c_str ( ) ) ;
item . m_display_desc = HUD : : GET_FILENAME_FOR_AUDIO_CONVERSATION ( item . m_display_desc . c_str ( ) ) ;
2023-04-02 00:37:26 +08:00
}
for ( auto it = peds . begin ( ) ; it ! = peds . end ( ) ; )
{
if ( CPedModelInfo * info = model_info : : get_model < CPedModelInfo * > ( it - > m_hash ) )
{
static std : : array < std : : string , 30 > ped_types = { " PLAYER_0 " , " PLAYER_1 " , " NETWORK_PLAYER " , " PLAYER_2 " , " CIVMALE " , " CIVFEMALE " , " COP " , " GANG_ALBANIAN " , " GANG_BIKER_1 " , " GANG_BIKER_2 " , " GANG_BIKER_2 " , " GANG_RUSSIAN " , " GANG_RUSSIAN_2 " , " GANG_RUSSIAN_2 " , " GANG_JAMAICAN " , " GANG_AFRICAN_AMERICAN " , " GANG_KOREAN " , " GANG_CHINESE_JAPANESE " , " GANG_PUERTO_RICAN " , " DEALER " , " MEDIC " , " FIREMAN " , " CRIMINAL " , " BUM " , " PROSTITUTE " , " SPECIAL " , " MISSION " , " SWAT " , " ANIMAL " , " ARMY " } ;
std : : strncpy ( it - > m_ped_type , ped_types [ info - > ped_type ] . c_str ( ) , sizeof ( it - > m_ped_type ) ) ;
+ + it ;
2023-04-06 20:01:23 +02:00
}
2023-04-02 00:37:26 +08:00
else
{
peds . erase ( it ) ;
2023-04-06 20:01:23 +02:00
}
2023-04-02 00:37:26 +08:00
}
2023-08-29 23:22:10 +02:00
translate_label = true ;
2023-04-02 00:37:26 +08:00
} ) ;
2023-08-29 23:22:10 +02:00
while ( ! translate_label )
2023-04-02 00:37:26 +08:00
{
if ( state ( ) = = eGtaDataUpdateState : : UPDATING )
script : : get_current ( ) - > yield ( ) ;
else
std : : this_thread : : sleep_for ( 100 ms ) ;
}
2022-10-19 00:30:32 +02:00
m_update_state = eGtaDataUpdateState : : IDLE ;
2023-03-01 21:27:15 +00:00
LOG ( INFO ) < < " Cache has been rebuilt. \n \t Peds: " < < peds . size ( ) < < " \n \t Vehicles: " < < vehicles . size ( )
2023-07-07 18:52:52 -04:00
< < " \n \t Weapons: " < < weapons . size ( ) < < " \n \t WeaponComponents: " < < weapon_components . size ( ) ;
2022-07-29 19:51:19 +08:00
2023-02-08 23:36:55 +01:00
LOG ( VERBOSE ) < < " Starting cache saving procedure... " ;
2023-07-07 18:52:52 -04:00
g_thread_pool - > push ( [ this , peds = std : : move ( peds ) , vehicles = std : : move ( vehicles ) , weapons = std : : move ( weapons ) , weapon_components = std : : move ( weapon_components ) ] {
2023-04-16 18:28:49 +00:00
const auto file_version = memory : : module ( " GTA5.exe " ) . size ( ) ;
2022-07-29 19:51:19 +08:00
2022-08-13 17:19:18 +08:00
{
2022-10-19 00:30:32 +02:00
const auto data_size = sizeof ( ped_item ) * peds . size ( ) ;
2023-07-20 22:46:32 +02:00
m_peds_cache . set_data ( std : : make_unique < uint8_t [ ] > ( data_size ) , data_size ) ;
2022-10-19 00:30:32 +02:00
std : : memcpy ( m_peds_cache . data ( ) , peds . data ( ) , data_size ) ;
2023-04-16 18:28:49 +00:00
m_peds_cache . set_header_version ( file_version ) ;
2022-10-19 00:30:32 +02:00
m_peds_cache . write ( ) ;
2022-07-29 19:51:19 +08:00
}
{
2022-10-19 00:30:32 +02:00
const auto data_size = sizeof ( vehicle_item ) * vehicles . size ( ) ;
2023-07-20 22:46:32 +02:00
m_vehicles_cache . set_data ( std : : make_unique < uint8_t [ ] > ( data_size ) , data_size ) ;
2022-10-19 00:30:32 +02:00
std : : memcpy ( m_vehicles_cache . data ( ) , vehicles . data ( ) , data_size ) ;
2022-07-29 19:51:19 +08:00
2023-04-16 18:28:49 +00:00
m_vehicles_cache . set_header_version ( file_version ) ;
2022-10-19 00:30:32 +02:00
m_vehicles_cache . write ( ) ;
}
2022-08-13 17:19:18 +08:00
2022-10-19 00:30:32 +02:00
{
2023-07-07 18:52:52 -04:00
m_weapons_cache . version_info . m_game_build = g_pointers - > m_gta . m_game_version ;
m_weapons_cache . version_info . m_online_version = g_pointers - > m_gta . m_online_version ;
m_weapons_cache . version_info . m_file_version = file_version ;
for ( auto weapon : weapons )
{
add_if_not_exists ( m_weapon_types , weapon . m_weapon_type ) ;
m_weapons_cache . weapon_map . insert ( { weapon . m_name , weapon } ) ;
}
2022-08-13 17:19:18 +08:00
2023-07-07 18:52:52 -04:00
for ( auto weapon_component : weapon_components )
{
m_weapons_cache . weapon_components . insert ( { weapon_component . m_name , weapon_component } ) ;
}
2023-07-08 17:54:59 +02:00
auto weapons_file = g_file_manager . get_project_file ( " ./cache/weapons.json " ) ;
2023-07-07 18:52:52 -04:00
std : : ofstream file ( weapons_file . get_path ( ) ) ;
try
{
nlohmann : : json weapons_file_json ;
weapons_file_json [ " weapons_cache " ] = m_weapons_cache ;
file < < weapons_file_json ;
file . flush ( ) ;
}
catch ( const std : : exception & exception )
{
LOG ( WARNING ) < < " Failed to write weapons JSON: " < < exception . what ( ) ;
}
2022-07-29 19:51:19 +08:00
}
2022-10-19 00:30:32 +02:00
LOG ( INFO ) < < " Finished writing cache to disk. " ;
2022-08-13 17:19:18 +08:00
2022-10-19 00:30:32 +02:00
load_data ( ) ;
} ) ;
2022-07-29 19:51:19 +08:00
}
2024-03-12 09:42:11 +01:00
}