fix: PetComponent crashing due to nullptr access

Resolves an issue where item is null but is accessed but not doing that code and instead consulting the EntityManager for a valid Entity, alongside nullifying the m_Owner objectID should the pet be destroyed and timer still exist.

Update PetComponent.cpp

Add nullptr check

Add back timer

Update PetComponent.cpp

speculative fix for a different crash

Why are we accessing something before checking if its null
This commit is contained in:
David Markowitz 2024-10-26 20:59:15 -07:00
parent 33a8efdd22
commit 0d218fc5c7
2 changed files with 19 additions and 18 deletions

View File

@ -795,8 +795,6 @@ void PetComponent::Wander() {
} }
void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
AddDrainImaginationTimer(item, fromTaming);
m_ItemId = item->GetId(); m_ItemId = item->GetId();
m_DatabaseId = item->GetSubKey(); m_DatabaseId = item->GetSubKey();
@ -807,6 +805,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
inventoryComponent->DespawnPet(); inventoryComponent->DespawnPet();
m_Owner = inventoryComponent->GetParent()->GetObjectID(); m_Owner = inventoryComponent->GetParent()->GetObjectID();
AddDrainImaginationTimer(fromTaming);
auto* owner = GetOwner(); auto* owner = GetOwner();
@ -859,17 +858,14 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
} }
} }
void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { void PetComponent::AddDrainImaginationTimer(bool fromTaming) {
if (Game::config->GetValue("pets_take_imagination") != "1") return; if (Game::config->GetValue("pets_take_imagination") != "1") return;
auto playerInventory = item->GetInventory(); auto* playerEntity = Game::entityManager->GetEntity(m_Owner);
if (!playerInventory) return; if (!playerEntity) {
LOG("owner was null or didnt exist!");
auto playerInventoryComponent = playerInventory->GetComponent(); return;
if (!playerInventoryComponent) return; }
auto playerEntity = playerInventoryComponent->GetParent();
if (!playerEntity) return;
auto playerDestroyableComponent = playerEntity->GetComponent<DestroyableComponent>(); auto playerDestroyableComponent = playerEntity->GetComponent<DestroyableComponent>();
if (!playerDestroyableComponent) return; if (!playerDestroyableComponent) return;
@ -878,12 +874,16 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
if (!fromTaming) playerDestroyableComponent->Imagine(-1); if (!fromTaming) playerDestroyableComponent->Imagine(-1);
// Set this to a variable so when this is called back from the player the timer doesn't fire off. // Set this to a variable so when this is called back from the player the timer doesn't fire off.
m_Parent->AddCallbackTimer(m_PetInfo.imaginationDrainRate, [playerDestroyableComponent, this, item]() { m_Parent->AddCallbackTimer(m_PetInfo.imaginationDrainRate, [this]() {
if (!playerDestroyableComponent) { const auto* owner = Game::entityManager->GetEntity(m_Owner);
LOG("No petComponent and/or no playerDestroyableComponent"); if (!owner) {
LOG("owner was null or didnt exist!");
return; return;
} }
const auto* playerDestroyableComponent = owner->GetComponent<DestroyableComponent>();
if (!playerDestroyableComponent) return;
// If we are out of imagination despawn the pet. // If we are out of imagination despawn the pet.
if (playerDestroyableComponent->GetImagination() == 0) { if (playerDestroyableComponent->GetImagination() == 0) {
this->Deactivate(); this->Deactivate();
@ -893,15 +893,13 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), eUseItemResponse::NoImaginationForPet); GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), eUseItemResponse::NoImaginationForPet);
} }
this->AddDrainImaginationTimer(item); this->AddDrainImaginationTimer();
}); });
} }
void PetComponent::Deactivate() { void PetComponent::Deactivate() {
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true);
GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress());
activePets.erase(m_Owner); activePets.erase(m_Owner);
m_Parent->Kill(); m_Parent->Kill();
@ -910,6 +908,8 @@ void PetComponent::Deactivate() {
if (owner == nullptr) return; if (owner == nullptr) return;
GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, owner->GetSystemAddress());
GameMessages::SendAddPetToPlayer(m_Owner, 0, u"", LWOOBJID_EMPTY, LOT_NULL, owner->GetSystemAddress()); GameMessages::SendAddPetToPlayer(m_Owner, 0, u"", LWOOBJID_EMPTY, LOT_NULL, owner->GetSystemAddress());
GameMessages::SendRegisterPetID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); GameMessages::SendRegisterPetID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress());
@ -1034,6 +1034,7 @@ Entity* PetComponent::GetParentEntity() const {
} }
PetComponent::~PetComponent() { PetComponent::~PetComponent() {
m_Owner = LWOOBJID_EMPTY;
} }
void PetComponent::SetPetNameForModeration(const std::string& petName) { void PetComponent::SetPetNameForModeration(const std::string& petName) {

View File

@ -205,7 +205,7 @@ public:
* *
* @param item The item that represents this pet in the inventory. * @param item The item that represents this pet in the inventory.
*/ */
void AddDrainImaginationTimer(Item* item, bool fromTaming = false); void AddDrainImaginationTimer(bool fromTaming = false);
private: private: