From 512a39e158b671b0791f98b597ecf09a8e14fe28 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 28 Aug 2021 19:05:52 +0200 Subject: [PATCH] Deal with Creatures being deleted before a battle they're part of. Signed-off-by: Deukhoofd --- src/Battling/Models/BattleSide.cpp | 2 +- src/Battling/Models/BattleSide.hpp | 1 + src/Battling/Models/Creature.cpp | 8 +++++++- src/Battling/Models/Creature.hpp | 2 +- tests/BattleTests/CreatureTests.cpp | 13 +++++++++++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Battling/Models/BattleSide.cpp b/src/Battling/Models/BattleSide.cpp index 53f46e2..85f480d 100644 --- a/src/Battling/Models/BattleSide.cpp +++ b/src/Battling/Models/BattleSide.cpp @@ -54,7 +54,7 @@ void BattleSide::SetCreature(ArbUt::OptionalBorrowedPtr creature, uint if (old.HasValue()) { old.GetValue()->SetOnBattleField(false); } - _creatures[index] = creature.GetValue(); + _creatures[index] = creature; if (!creature.HasValue()) { return; } diff --git a/src/Battling/Models/BattleSide.hpp b/src/Battling/Models/BattleSide.hpp index 0073cec..9aed63f 100644 --- a/src/Battling/Models/BattleSide.hpp +++ b/src/Battling/Models/BattleSide.hpp @@ -40,6 +40,7 @@ namespace CreatureLib::Battling { void SetChoice(BaseTurnChoice* choice); void ResetChoices() noexcept; + void ForceClearCreature(uint8_t index) { _creatures[index] = {}; } void SetCreature(ArbUt::OptionalBorrowedPtr creature, uint8_t index); const ArbUt::OptionalBorrowedPtr& GetCreature(uint8_t index) const; diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index aa8fc94..1309bc5 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -391,4 +391,10 @@ void CreatureLib::Battling::Creature::ClearStatus() { if (_battleData.Battle.HasValue()) { _battleData.Battle.GetValue()->TriggerEventListener(this, ""_cnc); } -} \ No newline at end of file +} + +Battling::Creature::~Creature() { + if (_battleData.OnBattleField && _battleData.Side.HasValue()) { + _battleData.Side.GetValue()->ForceClearCreature(_battleData.Index.GetCreatureIndex()); + } +} diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index 26ef4a2..1479fb7 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -75,7 +75,7 @@ namespace CreatureLib::Battling { const Library::TalentIndex& talent, const std::vector& attacks, bool allowedExperienceGain = true); - virtual ~Creature() = default; + virtual ~Creature(); virtual void Initialize() { RecalculateFlatStats(); diff --git a/tests/BattleTests/CreatureTests.cpp b/tests/BattleTests/CreatureTests.cpp index ec6b48f..16bc2d6 100644 --- a/tests/BattleTests/CreatureTests.cpp +++ b/tests/BattleTests/CreatureTests.cpp @@ -1,5 +1,6 @@ #ifdef TESTS_BUILD #include "../../extern/doctest.hpp" +#include "../../src/Battling/Models/Battle.hpp" #include "../../src/Battling/Models/CreateCreature.hpp" #include "../TestLibrary/TestLibrary.hpp" @@ -54,4 +55,16 @@ TEST_CASE("Override Creature talent") { delete creature; } +TEST_CASE("Creature can be deleted before battle is deleted") { + // This should not happen during normal battle executions, but can happen for certain GC solutions. We should not + // segfault in this case, but deal with it properly. + auto library = TestLibrary::Get(); + auto creature = CreateCreature(library, "testSpecies1"_cnc, 1).Create(); + auto battle = new Battle(library, {}); + auto side = battle->GetSides()[0]; + side->SetCreature(creature, 0); + delete creature; + delete battle; +} + #endif \ No newline at end of file