From c1b6ae585737eaf122e2c86865bf59c8a4eeed4a Mon Sep 17 00:00:00 2001 From: prharvey <2677507+prharvey@users.noreply.github.com> Date: Fri, 17 May 2024 12:48:07 +0100 Subject: [PATCH 1/2] Merge pull request #70660 from prharvey/hallu_flood_fill Handle hallucinations in the reachability zones flood fill. --- src/creature_tracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature_tracker.cpp b/src/creature_tracker.cpp index b0a70a1028c29..a1d7e570893be 100644 --- a/src/creature_tracker.cpp +++ b/src/creature_tracker.cpp @@ -386,7 +386,7 @@ void creature_tracker::flood_fill_zone( const Creature &origin ) return false; }, [this]( const tripoint_bub_ms & loc ) { - Creature *creature = this->creature_at( loc ); + Creature *creature = this->creature_at( loc, true ); if( creature ) { const int n = zone_number_ * zone_tick_; creatures_by_zone_and_faction_[n][creature->get_monster_faction()].push_back( creature ); From 185dd7c2ea51be0887fcd6462df9737475157af3 Mon Sep 17 00:00:00 2001 From: prharvey <2677507+prharvey@users.noreply.github.com> Date: Fri, 17 May 2024 12:50:41 +0100 Subject: [PATCH 2/2] Merge pull request #70687 from prharvey/reachability_fix Fix crash from reachability zones checking dead NPCs. --- src/creature_tracker.cpp | 37 ++++++++++++++++++++++++++++--------- src/creature_tracker.h | 17 ++++++++++++----- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/creature_tracker.cpp b/src/creature_tracker.cpp index a1d7e570893be..168953c289b80 100644 --- a/src/creature_tracker.cpp +++ b/src/creature_tracker.cpp @@ -8,6 +8,7 @@ #include "cata_assert.h" #include "debug.h" #include "flood_fill.h" +#include "game.h" #include "map.h" #include "mongroup.h" #include "monster.h" @@ -170,7 +171,6 @@ void creature_tracker::remove( const monster &critter ) } remove_from_location_map( critter ); - removed_.emplace( iter->get() ); removed_this_turn_.emplace( *iter ); monsters_list.erase( iter ); } @@ -179,7 +179,6 @@ void creature_tracker::clear() { monsters_list.clear(); monsters_by_location.clear(); - removed_.clear(); removed_this_turn_.clear(); creatures_by_zone_and_faction_.clear(); invalidate_reachability_cache(); @@ -193,6 +192,27 @@ void creature_tracker::rebuild_cache() } } +bool creature_tracker::is_present( Creature *creature ) const +{ + if( creature->is_monster() ) { + if( const auto iter = monsters_by_location.find( creature->get_location() ); + iter != monsters_by_location.end() ) { + if( static_cast( iter->second.get() ) == creature ) { + return !iter->second->is_dead(); + } + } + } else if( creature->is_avatar() ) { + return true; + } else if( creature->is_npc() ) { + for( const shared_ptr_fast &cur_npc : active_npc ) { + if( static_cast( cur_npc.get() ) == creature ) { + return !cur_npc->is_dead(); + } + } + } + return false; +} + void creature_tracker::swap_positions( monster &first, monster &second ) { if( first.get_location() == second.get_location() ) { @@ -265,7 +285,6 @@ void creature_tracker::remove_dead() monster *const critter = iter->get(); if( critter->is_dead() ) { remove_from_location_map( *critter ); - removed_.insert( critter ); iter = monsters_list.erase( iter ); } else { ++iter; @@ -329,7 +348,6 @@ void creature_tracker::flood_fill_zone( const Creature &origin ) { if( dirty_ ) { creatures_by_zone_and_faction_.clear(); - removed_.clear(); zone_tick_ = zone_tick_ > 0 ? -1 : 1; zone_number_ = 1; dirty_ = false; @@ -386,11 +404,12 @@ void creature_tracker::flood_fill_zone( const Creature &origin ) return false; }, [this]( const tripoint_bub_ms & loc ) { - Creature *creature = this->creature_at( loc, true ); - if( creature ) { - const int n = zone_number_ * zone_tick_; - creatures_by_zone_and_faction_[n][creature->get_monster_faction()].push_back( creature ); - creature->set_reachable_zone( n ); + if( Creature *creature = this->creature_at( loc, true ) ) { + if( shared_ptr_fast ptr = g->shared_from( *creature ) ) { + const int n = zone_number_ * zone_tick_; + creatures_by_zone_and_faction_[n][creature->get_monster_faction()].emplace_back( std::move( ptr ) ); + creature->set_reachable_zone( n ); + } } } ); if( zone_number_ == std::numeric_limits::max() ) { diff --git a/src/creature_tracker.h b/src/creature_tracker.h index d1f1c08a7de29..e4c1d6e8e1e31 100644 --- a/src/creature_tracker.h +++ b/src/creature_tracker.h @@ -148,6 +148,9 @@ class creature_tracker void rebuild_cache(); + // If the creature is in the tracker. + bool is_present( Creature *creature ) const; + std::list> active_npc; // NOLINT(cata-serialize) std::vector> monsters_list; // NOLINTNEXTLINE(cata-serialize) @@ -165,9 +168,8 @@ class creature_tracker bool dirty_ = true; // NOLINT(cata-serialize) int zone_tick_ = 1; // NOLINT(cata-serialize) int zone_number_ = 0; // NOLINT(cata-serialize) - std::unordered_map>> + std::unordered_map>>> creatures_by_zone_and_faction_; // NOLINT(cata-serialize) - std::unordered_set removed_; // NOLINT(cata-serialize) friend game; }; @@ -192,15 +194,20 @@ Creature *creature_tracker::find_reachable( const Creature &origin, FactionPredi const auto map_iter = creatures_by_zone_and_faction_.find( origin.get_reachable_zone() ); if( map_iter != creatures_by_zone_and_faction_.end() ) { - for( const auto& [faction, creatures] : map_iter->second ) { + for( auto& [faction, creatures] : map_iter->second ) { if( !faction_fn( faction ) ) { continue; } - for( Creature *other : creatures ) { - if( removed_.count( other ) == 0 ) { + for( std::size_t i = 0; i < creatures.size(); ) { + if( Creature *other = creatures[i].get(); is_present( other ) ) { if( creature_fn( other ) ) { return other; } + ++i; + } else { + using std::swap; + swap( creatures[i], creatures.back() ); + creatures.pop_back(); } } }