From 55c436af263ffd5460f690a28f0a920798126845 Mon Sep 17 00:00:00 2001 From: Olanti Date: Tue, 31 Oct 2023 13:59:57 +0300 Subject: [PATCH] fix: crash in ranged accuracy test related to dead NPC cleanup (#3309) Use weak_ptr for killer pointer --- src/character.cpp | 2 +- src/creature.cpp | 10 +++++----- src/creature.h | 5 +++-- src/npc.cpp | 8 ++++---- src/savegame_json.cpp | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/character.cpp b/src/character.cpp index 4560fc50d369..b74f734c10b9 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -8525,7 +8525,7 @@ void Character::apply_damage( Creature *source, bodypart_id hurt, int dam, if( is_dead_state() ) { // if the player killed himself, add it to the kill count list - if( !is_npc() && !killer && source == g->u.as_character() ) { + if( !is_npc() && !get_killer() && source == g->u.as_character() ) { g->events().send( get_player_character().getID(), getID(), get_name() ); } diff --git a/src/creature.cpp b/src/creature.cpp index 201b9ff58d9a..eac0a20c2d7f 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -102,7 +102,7 @@ Creature::Creature() { moves = 0; pain = 0; - killer = nullptr; + killer.reset(); speed_base = 100; underwater = false; @@ -1466,15 +1466,15 @@ bool Creature::in_sleep_state() const */ Creature *Creature::get_killer() const { - return killer; + return killer.lock().get(); } -void Creature::set_killer( Creature *const killer ) +void Creature::set_killer( Creature *nkiller ) { // Only the first killer will be stored, calling set_killer again with a different // killer would mean it's called on a dead creature and therefore ignored. - if( killer != nullptr && !killer->is_fake() && this->killer == nullptr ) { - this->killer = killer; + if( !get_killer() && nkiller && !nkiller->is_fake() ) { + killer = g->shared_from( *nkiller ); } } diff --git a/src/creature.h b/src/creature.h index fb67e2d6e94e..253ea4751872 100644 --- a/src/creature.h +++ b/src/creature.h @@ -19,6 +19,7 @@ #include "units.h" #include "cached_options.h" #include "enums.h" +#include "memory_fast.h" enum game_message_type : int; class nc_color; @@ -809,8 +810,8 @@ class Creature effects_map get_all_effects() const; protected: - Creature *killer = nullptr; // whoever killed us. this should be NULL unless we are dead - void set_killer( Creature *killer ); + weak_ptr_fast killer; // whoever killed us. this should be NULL unless we are dead + void set_killer( Creature *nkiller ); /** * Processes one effect on the Creature. diff --git a/src/npc.cpp b/src/npc.cpp index bb470113872a..0c1f2906b041 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -2517,11 +2517,11 @@ void npc::die( Creature *nkiller ) add_msg( _( "%s dies!" ), name ); } - if( Character *ch = dynamic_cast( killer ) ) { + if( Character *ch = dynamic_cast( get_killer() ) ) { g->events().send( ch->getID(), getID(), get_name() ); } - if( killer == &g->u && ( !guaranteed_hostile() || hit_by_player ) ) { + if( get_killer() == &g->u && ( !guaranteed_hostile() || hit_by_player ) ) { bool cannibal = g->u.has_trait( trait_CANNIBAL ); bool psycho = g->u.has_trait( trait_PSYCHOPATH ) || g->u.has_trait( trait_KILLER ); if( g->u.has_trait( trait_SAPIOVORE ) || psycho ) { @@ -2533,14 +2533,14 @@ void npc::die( Creature *nkiller ) } } - if( killer == &g->u && g->u.has_trait( trait_KILLER ) ) { + if( get_killer() == &g->u && g->u.has_trait( trait_KILLER ) ) { const translation snip = SNIPPET.random_from_category( "killer_on_kill" ).value_or( translation() ); g->u.add_msg_if_player( m_good, "%s", snip ); g->u.add_morale( MORALE_KILLER_HAS_KILLED, 5, 10, 6_hours, 4_hours ); g->u.rem_morale( MORALE_KILLER_NEED_TO_KILL ); } - if( killer == &g->u && g->u.has_trait( trait_PROF_FERAL ) ) { + if( get_killer() == &g->u && g->u.has_trait( trait_PROF_FERAL ) ) { if( !g->u.has_effect( effect_feral_killed_recently ) ) { g->u.add_msg_if_player( m_good, _( "The voices in your head quiet down a bit." ) ); } diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 44f7bfa47aa0..7b4a4677e606 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -3081,7 +3081,7 @@ void Creature::load( const JsonObject &jsin ) jsin.read( "moves", moves ); jsin.read( "pain", pain ); - killer = nullptr; // see Creature::load + killer.reset(); if( jsin.has_object( "effects" ) ) { // Because JSON requires string keys we need to convert back to our bp keys