Loading...   

  • Created By Uleat On: 03:39 PM September 15, 2014
  • Link

 zone/hate_list.cpp |  6 ++++++
 zone/mob.cpp       | 46 +++++++++++++++++++++++++++-------------------
 2 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp
index f266158..291584c 100644
--- a/zone/hate_list.cpp
+++ b/zone/hate_list.cpp
@@ -303,6 +303,10 @@ Mob *HateList::GetTop(Mob *center)
 				continue;
 			}
 
+			// NPC::IsUnderWaterOnly() returns an unsafe call to *NPCTypeData and is crashing zones in ShutDown() mode (since the instance was consumed)
+
+			// option 2(a): add 'NPC::HasNPCTypeData()' check (not currently defined)
+			// if (center->IsNPC() && center->CastToNPC()->HasNPCTypeData() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
 			if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
 				if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
 					skipped_count++;
@@ -421,6 +425,8 @@ Mob *HateList::GetTop(Mob *center)
 		while(iterator != list.end())
 		{
 			tHateEntry *cur = (*iterator);
+			// option 2(b): add 'NPC::HasNPCTypeData()' check (not currently defined)
+			// if (center->IsNPC() && center->CastToNPC()->HasNPCTypeData() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
 			if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
 				if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
 					skipped_count++;
diff --git a/zone/mob.cpp b/zone/mob.cpp
index fdce628..4926f17 100644
--- a/zone/mob.cpp
+++ b/zone/mob.cpp
@@ -391,38 +391,46 @@ Mob::Mob(const char* in_name,
 
 Mob::~Mob()
 {
+	// option 1: reorganize ~Mob() to only process 'active zone' actions if Zone::ZoneLoaded is true
+	// (this has the added benefit of not wasting resources on a zone in shutdown mode - client packets? seriously??)
 	AI_Stop();
-	if (GetPet()) {
-		if (GetPet()->Charmed())
-			GetPet()->BuffFadeByEffect(SE_Charm);
-		else
-			SetPet(0);
-	}
-
-	EQApplicationPacket app;
-	CreateDespawnPacket(&app, !IsCorpse());
-	Corpse* corpse = entity_list.GetCorpseByID(GetID());
-	if(!corpse || (corpse && !corpse->IsPlayerCorpse()))
-		entity_list.QueueClients(this, &app, true);
 
-	entity_list.RemoveFromTargets(this, true);
-
-	if(trade) {
+	if (trade) {
 		Mob *with = trade->With();
-		if(with && with->IsClient()) {
+		if (with && with->IsClient()) {
 			with->CastToClient()->FinishTrade(with);
 			with->trade->Reset();
 		}
 		delete trade;
 	}
 
-	if(HadTempPets()){
-		entity_list.DestroyTempPets(this);
+	if (zone->IsLoaded()) { // actions only required for an active zone
+		if (GetPet()) {
+			if (GetPet()->Charmed())
+				GetPet()->BuffFadeByEffect(SE_Charm);
+			else
+				SetPet(nullptr); // this could be where the trade-with-pet crash was occuring since trade was previously processed after this action
+		}
+
+		EQApplicationPacket app;
+		CreateDespawnPacket(&app, !IsCorpse());
+		Corpse* corpse = entity_list.GetCorpseByID(GetID());
+		if (!corpse || (corpse && !corpse->IsPlayerCorpse()))
+			entity_list.QueueClients(this, &app, true);
+
+		// BUG: procedures further down this jump check for data whose reference has already been consumed by Zone::ShutDown()... (option 2)
+		entity_list.RemoveFromTargets(this, true);
+
+		if (HadTempPets())
+			entity_list.DestroyTempPets(this);
+
+		entity_list.UnMarkNPC(GetID());
 	}
-	entity_list.UnMarkNPC(GetID());
+
 	safe_delete(PathingLOSCheckTimer);
 	safe_delete(PathingRouteUpdateTimerShort);
 	safe_delete(PathingRouteUpdateTimerLong);
+
 	UninitializeBuffSlots();
 }
 

Raw Paste Data