Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throttle NPC item search activity alternative #33885

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "calendar.h"
#include "faction.h"
#include "line.h"
#include "lru_cache.h"
#include "optional.h"
#include "pimpl.h"
#include "player.h"
Expand Down Expand Up @@ -495,6 +496,8 @@ struct npc_short_term_cache {
std::vector<sphere> dangerous_explosives;

std::map<direction, float> threat_map;
// Cache of locations the NPC has searched recently in npc::find_item()
lru_cache<tripoint, int> searched_tiles;
};

// DO NOT USE! This is old, use strings as talk topic instead, e.g. "TALK_AGREE_FOLLOW" instead of
Expand Down
40 changes: 34 additions & 6 deletions src/npcmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2577,7 +2577,6 @@ void npc::find_item()
}

if( is_player_ally() && !rules.has_flag( ally_rule::allow_pick_up ) ) {

// Grabbing stuff not allowed by our "owner"
return;
}
Expand Down Expand Up @@ -2670,34 +2669,63 @@ void npc::find_item()
continue;
}

const tripoint abs_p = global_square_location() - pos() + p;
const int prev_num_items = ai_cache.searched_tiles.get( abs_p, -1 );
// Prefetch the number of items present so we can bail out if we already checked here.
const map_stack m_stack = g->m.i_at( p );
int num_items = m_stack.size();
const optional_vpart_position vp = g->m.veh_at( p );
if( vp ) {
const cata::optional<vpart_reference> cargo = vp.part_with_feature( VPFLAG_CARGO, true );
if( cargo ) {
vehicle_stack v_stack = cargo->vehicle().get_items( cargo->part_index() );
num_items += v_stack.size();
}
}
if( prev_num_items == num_items ) {
continue;
}
auto cache_tile = [this, &abs_p, num_items, &wanted]() {
if( wanted == nullptr ) {
ai_cache.searched_tiles.insert( 1000, abs_p, num_items );
}
};
bool can_see = false;
if( g->m.sees_some_items( p, *this ) && sees( p ) ) {
for( const item &it : g->m.i_at( p ) ) {
can_see = true;
for( const item &it : m_stack ) {
consider_item( it, p );
}
}

// Allow terrain check without sight, because it would cost more CPU than it is worth
consider_terrain( p );
// Not cached because it gets checked once and isn't expected to change.
if( can_see || sees( p ) ) {
can_see = true;
consider_terrain( p );
}

const optional_vpart_position vp = g->m.veh_at( p );
if( !vp || vp->vehicle().is_moving() || !sees( p ) ) {
if( !vp || vp->vehicle().is_moving() || !( can_see || sees( p ) ) ) {
cache_tile();
continue;
}
const cata::optional<vpart_reference> cargo = vp.part_with_feature( VPFLAG_CARGO, true );
static const std::string locked_string( "LOCKED" );
// TODO: Let player know what parts are safe from NPC thieves
if( !cargo || cargo->has_feature( locked_string ) ) {
cache_tile();
continue;
}

static const std::string cargo_locking_string( "CARGO_LOCKING" );
if( vp.part_with_feature( cargo_locking_string, true ) ) {
cache_tile();
continue;
}

for( const item &it : cargo->vehicle().get_items( cargo->part_index() ) ) {
consider_item( it, p );
}
cache_tile();
}

if( wanted != nullptr ) {
Expand Down