From 7aee83d5b2c8f7313b4b207d3802b17be980f7f5 Mon Sep 17 00:00:00 2001 From: CLIDragon <84266961+CLIDragon@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:06:38 +1000 Subject: [PATCH 1/2] [Perf] Improve efficiency of vehicle code. * Add a new function, has_parts() which takes a list of flags and checks if the vehicle has parts which have them. Equivalent to calling has_part multiple times, but more performant. * Replace get_all_parts() with boarded_parts() in vehicle::get_driver(). Each part would check all the parts that its mounted to to see whether they had a passenger, requiring a lot of redundant checks. --- src/vehicle.cpp | 45 +++++++++++++++++++++++++++++++++++---------- src/vehicle.h | 14 ++++++++++++++ src/vehicle_use.cpp | 4 ++-- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 993d680e45e28..4033c7dbcfda0 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -24,6 +24,7 @@ #include "avatar.h" #include "bionics.h" #include "cata_assert.h" +#include "cata_bitset.h" #include "cata_utility.h" #include "character.h" #include "clzones.h" @@ -3032,6 +3033,28 @@ bool vehicle::has_part( const std::string &flag, bool enabled ) const return false; } +tiny_bitset vehicle::has_parts( const std::vector &flags, bool enabled ) const +{ + tiny_bitset ret = tiny_bitset( flags.size() ); + for( const vpart_reference &vpr : get_all_parts() ) { + vehicle_part &part = vpr.part(); + if( !part.removed && ( !enabled || part.enabled ) && !part.is_broken() ) { + // Check whether the part has any of the flags we are looking for + for( int i = 0; i < flags.size(); i++ ) { + const std::string &flag = flags[i]; + if( part.info().has_flag( flag ) ) { + ret.set( i ); + } + } + // Exit early if we have found parts matching each flag. + if( ret.all() ) { + return ret; + } + } + } + return ret; +} + bool vehicle::has_part( const tripoint &pos, const std::string &flag, bool enabled ) const { const tripoint relative_pos = pos - global_pos3(); @@ -3669,9 +3692,8 @@ bool vehicle::has_driver() const Character *vehicle::get_driver() const { - // TODO: Gotta be a better way than this... - for( const vpart_reference &vp : get_all_parts() ) { - Character *occupant = vp.get_passenger(); + for( const int vp : boarded_parts() ) { + Character *occupant = get_passenger( vp ); if( occupant && player_in_control( *occupant ) ) { return occupant; } @@ -6031,15 +6053,17 @@ void vehicle::idle( bool on_map ) } } - if( has_part( "STEREO", true ) ) { + tiny_bitset flags = has_parts( { "STEREO", "CHIMES", "CRASH_TERRAIN_AROUND" }, true ); + + if( flags.test( 0 ) ) { play_music(); } - if( has_part( "CHIMES", true ) ) { + if( flags.test( 1 ) ) { play_chimes(); } - if( has_part( "CRASH_TERRAIN_AROUND", true ) ) { + if( flags.test( 2 ) ) { crash_terrain_around(); } @@ -6064,16 +6088,17 @@ void vehicle::idle( bool on_map ) void vehicle::on_move() { - if( has_part( "TRANSFORM_TERRAIN", true ) ) { + tiny_bitset part_flags = has_parts( { "TRANSFORM_TERRAIN", "SCOOP", "PLANTER", "REAPER" }, true ); + if( part_flags.test( 0 ) ) { transform_terrain(); } - if( has_part( "SCOOP", true ) ) { + if( part_flags.test( 1 ) ) { operate_scoop(); } - if( has_part( "PLANTER", true ) ) { + if( part_flags.test( 2 ) ) { operate_planter(); } - if( has_part( "REAPER", true ) ) { + if( part_flags.test( 3 ) ) { operate_reaper(); } diff --git a/src/vehicle.h b/src/vehicle.h index d5f1ebeacd668..cd0479c0ab4e4 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -21,6 +21,7 @@ #include "active_item_cache.h" #include "calendar.h" +#include "cata_bitset.h" #include "character_id.h" #include "clzones.h" #include "colony.h" @@ -1289,6 +1290,19 @@ class vehicle */ bool has_part( const tripoint &pos, const std::string &flag, bool enabled = false ) const; + /** + * Check if vehicle has at least one unbroken part with each of the specified flags + * + * e.g. has_parts({"F1", "F2", "F3"}), the first bit will hold whether the vehicle has + * F1, the second F2, and so on. + * + * @param flags Specified flags to search parts for. This should be <= 56 entries long. + * @param enabled if set part must also be enabled to be considered + * @returns true if part is found for each flag. The index of the resultant bitset is the + * same as in flags. + */ + tiny_bitset has_parts( const std::vector &flags, bool enabled = false ) const; + /** * Get all enabled, available, unbroken vehicle parts at specified position * @param pos position to check diff --git a/src/vehicle_use.cpp b/src/vehicle_use.cpp index 94c90ec53343a..240028d092a0d 100644 --- a/src/vehicle_use.cpp +++ b/src/vehicle_use.cpp @@ -291,7 +291,7 @@ void vehicle::build_electronics_menu( veh_menu &menu ) .on_submit( [this] { control_doors(); } ); } - if( camera_on || ( has_part( "CAMERA" ) && has_part( "CAMERA_CONTROL" ) ) ) { + if( camera_on || ( has_parts( {"CAMERA", "CAMERA_CONTROL"} ).all() ) ) { menu.add( camera_on ? colorize( _( "Turn off camera system" ), c_pink ) : _( "Turn on camera system" ) ) @@ -1842,7 +1842,7 @@ void vehicle::build_interact_menu( veh_menu &menu, const tripoint &p, bool with_ const bool remote = g->remoteveh() == this; const bool has_electronic_controls = remote - ? has_part( "CTRL_ELECTRONIC" ) || has_part( "REMOTE_CONTROLS" ) + ? has_parts( {"CTRL_ELECTRONIC", "REMOTE_CONTROL"} ).any() : has_part_here( "CTRL_ELECTRONIC" ); const bool controls_here = has_part_here( "CONTROLS" ); const bool player_is_driving = get_player_character().controlling_vehicle; From db8dd3ab19363de6bff6d78f07ec03de0c753b67 Mon Sep 17 00:00:00 2001 From: CLIDragon <84266961+CLIDragon@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:07:58 +1000 Subject: [PATCH 2/2] Update src/vehicle.cpp Co-authored-by: xcdxbaxa9 <187881463+xcdxbaxa9@users.noreply.github.com> --- src/vehicle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 4033c7dbcfda0..efd3a367f525f 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -3040,7 +3040,7 @@ tiny_bitset vehicle::has_parts( const std::vector &flags, bool enab vehicle_part &part = vpr.part(); if( !part.removed && ( !enabled || part.enabled ) && !part.is_broken() ) { // Check whether the part has any of the flags we are looking for - for( int i = 0; i < flags.size(); i++ ) { + for( size_t i = 0; i < flags.size(); i++ ) { const std::string &flag = flags[i]; if( part.info().has_flag( flag ) ) { ret.set( i );