Skip to content

Commit

Permalink
[Perf] Improve efficiency of vehicle code.
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
CLIDragon committed Nov 11, 2024
1 parent 60cf27e commit 7aee83d
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 12 deletions.
45 changes: 35 additions & 10 deletions src/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<std::string> &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();
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
}

Expand All @@ -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();
}

Expand Down
14 changes: 14 additions & 0 deletions src/vehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<std::string> &flags, bool enabled = false ) const;

/**
* Get all enabled, available, unbroken vehicle parts at specified position
* @param pos position to check
Expand Down
4 changes: 2 additions & 2 deletions src/vehicle_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() ) ) {

Check failure on line 294 in src/vehicle_use.cpp

View workflow job for this annotation

GitHub Actions / build (src)

Redundant parentheses. [cata-redundant-parentheses,-warnings-as-errors]
menu.add( camera_on
? colorize( _( "Turn off camera system" ), c_pink )
: _( "Turn on camera system" ) )
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 7aee83d

Please sign in to comment.