From b79030310baf272cbd2ce08bb926982322ee9f65 Mon Sep 17 00:00:00 2001 From: Zimp Date: Fri, 18 Jul 2025 23:25:28 -0500 Subject: [PATCH] [Fix] Fix crash from lingering spawn2 reference in NPCs. --- zone/attack.cpp | 7 +++++-- zone/entity.cpp | 2 +- zone/gm_commands/advnpcspawn.cpp | 6 +++--- zone/gm_commands/spawnfix.cpp | 2 +- zone/gm_commands/wpadd.cpp | 2 +- zone/npc.cpp | 26 +++++++++++++++----------- zone/npc.h | 4 ++-- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 9c6581a32..783b11444 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2611,8 +2611,11 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy safe_delete(app); - if (respawn2) { - respawn2->DeathReset(1); + if (respawn2_id) { + auto respawn2 = GetSpawn(); + if (respawn2) { + respawn2->DeathReset(1); + } } if (killer_mob && GetClass() != Class::LDoNTreasure) { diff --git a/zone/entity.cpp b/zone/entity.cpp index 0b94fc7ac..37abd0b75 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -520,7 +520,7 @@ void EntityList::MobProcess() old_client_count = numclients; - Spawn2* s2 = mob->CastToNPC()->respawn2; + Spawn2* s2 = mob->CastToNPC()->GetSpawn(); // Perform normal mob processing if any of these are true: // -- zone is not empty diff --git a/zone/gm_commands/advnpcspawn.cpp b/zone/gm_commands/advnpcspawn.cpp index 235362f3f..6bd2c6d6b 100755 --- a/zone/gm_commands/advnpcspawn.cpp +++ b/zone/gm_commands/advnpcspawn.cpp @@ -188,7 +188,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } auto target = c->GetTarget()->CastToNPC(); - auto spawn2 = target->respawn2; + auto spawn2 = target->GetSpawn(); if (!spawn2) { c->Message(Chat::White, "Failed to delete spawn because NPC has no Spawn2."); return; @@ -297,7 +297,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } auto target = c->GetTarget()->CastToNPC(); - auto spawn2 = target->respawn2; + auto spawn2 = target->GetSpawn(); if (!spawn2) { c->Message(Chat::White, "Failed to edit respawn because NPC has no Spawn2."); return; @@ -434,7 +434,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } auto target = c->GetTarget()->CastToNPC(); - auto spawn2 = target->respawn2; + auto spawn2 = target->GetSpawn(); if (!spawn2) { c->Message(Chat::White, "Failed to move spawn because NPC has no Spawn2."); return; diff --git a/zone/gm_commands/spawnfix.cpp b/zone/gm_commands/spawnfix.cpp index 7cfe33e7b..2ef66c680 100755 --- a/zone/gm_commands/spawnfix.cpp +++ b/zone/gm_commands/spawnfix.cpp @@ -8,7 +8,7 @@ void command_spawnfix(Client* c, const Seperator* sep) } auto target = c->GetTarget()->CastToNPC(); - auto spawn2 = target->respawn2; + auto spawn2 = target->GetSpawn(); if (!spawn2) { c->Message(Chat::White, "Failed to fix spawn, the spawn must not exist in the database."); diff --git a/zone/gm_commands/wpadd.cpp b/zone/gm_commands/wpadd.cpp index b8f114c7b..a1e9abff6 100755 --- a/zone/gm_commands/wpadd.cpp +++ b/zone/gm_commands/wpadd.cpp @@ -5,7 +5,7 @@ void command_wpadd(Client *c, const Seperator *sep) int type1 = 0, type2 = 0, pause = 0; // Defaults for a new grid Mob *target = c->GetTarget(); if (target && target->IsNPC()) { - Spawn2 *s2info = target->CastToNPC()->respawn2; + Spawn2 *s2info = target->CastToNPC()->GetSpawn(); if (s2info == nullptr) { c->Message( Chat::White, diff --git a/zone/npc.cpp b/zone/npc.cpp index 1c70da2c4..eefd974b1 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -156,7 +156,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi NPCTypedata = npc_type_data; NPCTypedata_ours = nullptr; - respawn2 = in_respawn; + respawn2_id = in_respawn ? in_respawn->GetID() : 0; swarm_timer.Disable(); @@ -870,11 +870,14 @@ void NPC::Depop(bool start_spawn_timer) { } p_depop = true; - if (respawn2) { - if (start_spawn_timer) { - respawn2->DeathReset(); - } else { - respawn2->Depop(); + if (respawn2_id) { + auto respawn2 = entity_list.GetSpawnByID(respawn2_id); + if (respawn2) { + if (start_spawn_timer) { + respawn2->DeathReset(); + } else { + respawn2->Depop(); + } } } } @@ -1357,10 +1360,11 @@ uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand( uint32 respawn_time = 1200; uint32 spawn_id = 0; + Spawn2 *respawn2 = n->respawn2_id ? entity_list.GetSpawnByID(n->respawn2_id) : nullptr; if (in_respawn_time) { respawn_time = in_respawn_time; - } else if (n->respawn2 && n->respawn2->RespawnTimer()) { - respawn_time = n->respawn2->RespawnTimer(); + } else if (respawn2 && respawn2->RespawnTimer()) { + respawn_time = respawn2->RespawnTimer(); } auto s2 = Spawn2Repository::NewEntity(); @@ -1420,7 +1424,7 @@ uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client* c, NPC* n) uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const std::string& zone, Client* c, NPC* n, uint32 remove_spawngroup_id) { - if (!n->respawn2) { + if (!n->respawn2_id) { return 0; } @@ -1428,7 +1432,7 @@ uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const std::string& zone, Cli *this, fmt::format( "`id` = {} AND `zone` = '{}' AND `spawngroupID` = {}", - n->respawn2->GetID(), + n->respawn2_id, zone, n->GetSpawnGroupId() ) @@ -2778,7 +2782,7 @@ void NPC::LevelScale() { uint32 NPC::GetSpawnPointID() const { - return respawn2 ? respawn2->GetID() : 0; + return respawn2_id; } void NPC::NPCSlotTexture(uint8 slot, uint32 texture) diff --git a/zone/npc.h b/zone/npc.h index 31a4e09f9..52d709034 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -248,7 +248,7 @@ public: uint16 GetWaypointMax() const { return wp_m; } int32 GetGrid() const { return grid; } - Spawn2* GetSpawn() { return respawn2 ? respawn2 : nullptr; } + Spawn2* GetSpawn() { return respawn2_id ? entity_list.GetSpawnByID(respawn2_id) : nullptr; } uint32 GetSpawnGroupId() const { return spawn_group_id; } uint32 GetSpawnPointID() const; @@ -417,7 +417,7 @@ public: bool IsProximitySet(); NPCProximity* proximity; - Spawn2* respawn2; + uint32 respawn2_id; QGlobalCache *GetQGlobals() { return qGlobals; } QGlobalCache *CreateQGlobals() { qGlobals = new QGlobalCache(); return qGlobals; }