From 6ae3e36be081d52466bf7fc4a4fb84932acce3c3 Mon Sep 17 00:00:00 2001 From: David Seguin Date: Wed, 12 Jan 2022 01:27:35 -0500 Subject: [PATCH] Performance: Cache NPC goal (#54312) The goal cache is invalidated when the NPC moves to a different OMT. --- src/npc.h | 7 +++++++ src/npcmove.cpp | 36 ++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/npc.h b/src/npc.h index b05cd096dbf20..3fe34686c8830 100644 --- a/src/npc.h +++ b/src/npc.h @@ -591,6 +591,11 @@ struct npc_short_term_cache { cata::optional closest_enemy_to_friendly_distance() const; }; +struct npc_need_goal_cache { + tripoint_abs_omt goal; + tripoint_abs_omt omt_loc; +}; + // DO NOT USE! This is old, use strings as talk topic instead, e.g. "TALK_AGREE_FOLLOW" instead of // TALK_AGREE_FOLLOW. There is also convert_talk_topic which can convert the enumeration values to // the new string values (used to load old saves). @@ -1300,6 +1305,8 @@ class npc : public Character std::map complaints; npc_short_term_cache ai_cache; + + std::map goal_cache; public: const std::shared_ptr &get_current_attack() const { return ai_cache.current_attack; diff --git a/src/npcmove.cpp b/src/npcmove.cpp index fe5af77d66a2c..006d5bbcaf4b3 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -4190,20 +4190,28 @@ void npc::set_omt_destination() std::string dest_type; for( const auto &fulfill : needs ) { - // look for the closest occurrence of any of that locations terrain types - omt_find_params find_params; - for( const oter_type_str_id &elem : get_location_for( fulfill )->get_all_terrains() ) { - std::pair temp_pair; - temp_pair.first = elem.str(); - temp_pair.second = ot_match_type::type; - find_params.types.push_back( temp_pair ); - } - // note: no shuffle of `find_params.types` is needed, because `find_closest` - // disregards `types` order anyway, and already returns random result among - // those having equal minimal distance - find_params.search_range = 75; - find_params.existing_only = false; - goal = overmap_buffer.find_closest( surface_omt_loc, find_params ); + auto cache_iter = goal_cache.find( fulfill ); + if( cache_iter != goal_cache.end() && cache_iter->second.omt_loc == surface_omt_loc ) { + goal = cache_iter->second.goal; + } else { + // look for the closest occurrence of any of that locations terrain types + omt_find_params find_params; + for( const oter_type_str_id &elem : get_location_for( fulfill )->get_all_terrains() ) { + std::pair temp_pair; + temp_pair.first = elem.str(); + temp_pair.second = ot_match_type::type; + find_params.types.push_back( temp_pair ); + } + // note: no shuffle of `find_params.types` is needed, because `find_closest` + // disregards `types` order anyway, and already returns random result among + // those having equal minimal distance + find_params.search_range = 75; + find_params.existing_only = false; + goal = overmap_buffer.find_closest( surface_omt_loc, find_params ); + npc_need_goal_cache &cache = goal_cache[fulfill]; + cache.goal = goal; + cache.omt_loc = surface_omt_loc; + } omt_path.clear(); if( goal != overmap::invalid_tripoint ) { omt_path = overmap_buffer.get_travel_path( surface_omt_loc, goal, overmap_path_params::for_npc() );