Browse Source

SetQuestsRequired is now mutex protected, trying to prevent crash on deconstructor

image 3 years ago
parent
commit
a41aa0fa6d

+ 1 - 1
EQ2/source/WorldServer/GroundSpawn.h

@@ -47,7 +47,7 @@ public:
 		new_spawn->SetAttemptsPerHarvest(num_attempts_per_harvest);
 		new_spawn->SetGroundSpawnEntryID(groundspawn_id);
 		new_spawn->SetCollectionSkill(collection_skill.c_str());
-		new_spawn->SetQuestsRequired(GetQuestsRequired());
+		SetQuestsRequired(new_spawn);
 		new_spawn->forceMapCheck = forceMapCheck;
 		return new_spawn;
 	}

+ 1 - 1
EQ2/source/WorldServer/NPC.cpp

@@ -73,7 +73,7 @@ NPC::NPC(NPC* old_npc){
 		SetTotalPowerBase(old_npc->GetTotalPowerBase());		
 		faction_id = old_npc->faction_id;
 		movement_interrupted = false;
-		SetQuestsRequired(old_npc->GetQuestsRequired());
+		old_npc->SetQuestsRequired(this);
 		SetTransporterID(old_npc->GetTransporterID());
 
 		SetAttackType(old_npc->GetAttackType());

+ 1 - 1
EQ2/source/WorldServer/Object.cpp

@@ -87,7 +87,7 @@ Object*	Object::Copy(){
 	new_spawn->SetTotalPower(GetTotalPower());
 	new_spawn->SetHP(GetHP());
 	new_spawn->SetPower(GetPower());
-	new_spawn->SetQuestsRequired(GetQuestsRequired());
+	SetQuestsRequired(new_spawn);
 	new_spawn->SetTransporterID(GetTransporterID());
 	new_spawn->SetDeviceID(GetDeviceID());
 	new_spawn->SetSoundsDisabled(IsSoundsDisabled());

+ 23 - 9
EQ2/source/WorldServer/Spawn.cpp

@@ -113,6 +113,7 @@ Spawn::Spawn(){
 	pickup_item_id = 0;
 	pickup_unique_item_id = 0;
 	disable_sounds = false;
+	has_quests_required = false;
 }
 
 Spawn::~Spawn(){
@@ -125,6 +126,8 @@ Spawn::~Spawn(){
 	for(int32 i=0;i<secondary_command_list.size();i++){
 		safe_delete(secondary_command_list[i]);
 	}
+	secondary_command_list.clear();
+
 	RemoveSpawnFromGroup();
 	if (MMovementLocations)
 		MMovementLocations->writelock(__FUNCTION__, __LINE__);
@@ -142,13 +145,19 @@ Spawn::~Spawn(){
 	MMovementLoop.lock();
 	for (int32 i = 0; i < movement_loop.size(); i++)
 		safe_delete(movement_loop.at(i));
+	movement_loop.clear();
 	MMovementLoop.unlock();
 
+	m_requiredHistory.writelock(__FUNCTION__, __LINE__);
+	required_history.clear();
+	m_requiredHistory.releasewritelock(__FUNCTION__, __LINE__);
+
 	map<int32, vector<int16>* >::iterator rq_itr;
 	m_requiredQuests.writelock(__FUNCTION__, __LINE__);
 	for (rq_itr = required_quests.begin(); rq_itr != required_quests.end(); rq_itr++){
 		safe_delete(rq_itr->second);
 	}
+	required_quests.clear();
 	m_requiredQuests.releasewritelock(__FUNCTION__, __LINE__);
 
 	// just in case to make sure data is destroyed
@@ -1878,21 +1887,23 @@ bool Spawn::IsClientInMerchantLevelRange(Client* client, bool sendMessageIfDenie
 	return true;
 }
 
-void Spawn::SetQuestsRequired(map<int32, vector<int16>* >* quests){
-	if(quests){
+void Spawn::SetQuestsRequired(Spawn* new_spawn){
+	m_requiredQuests.writelock(__FUNCTION__, __LINE__);
+	if(required_quests.size() > 0){
 		map<int32, vector<int16>* >::iterator itr;
-		for(itr = quests->begin(); itr != quests->end(); itr++){
+		for(itr = required_quests.begin(); itr != required_quests.end(); itr++){
 			vector<int16>* quest_steps = itr->second;
 			for (int32 i = 0; i < quest_steps->size(); i++)
-				SetQuestsRequired(itr->first, quest_steps->at(i));
+				new_spawn->SetQuestsRequired(itr->first, quest_steps->at(i));
 		}
 	}
+	m_requiredQuests.releasewritelock(__FUNCTION__, __LINE__);
 }
 
 void Spawn::SetQuestsRequired(int32 quest_id, int16 quest_step){
 	m_requiredQuests.writelock(__FUNCTION__, __LINE__);
 	if (required_quests.count(quest_id) == 0)
-		required_quests[quest_id] = new vector<int16>;
+		required_quests.insert(make_pair(quest_id, new vector<int16>));
 	else{
 		for (int32 i = 0; i < required_quests[quest_id]->size(); i++){
 			if (required_quests[quest_id]->at(i) == quest_step){
@@ -1901,10 +1912,17 @@ void Spawn::SetQuestsRequired(int32 quest_id, int16 quest_step){
 			}
 		}
 	}
+
+	has_quests_required = true;
 	required_quests[quest_id]->push_back(quest_step);
 	m_requiredQuests.releasewritelock(__FUNCTION__, __LINE__);
 }
 
+bool Spawn::HasQuestsRequired()
+{
+	return has_quests_required;
+}
+
 void Spawn::SetRequiredHistory(int32 event_id, int32 value1, int32 value2){
 	LUAHistory set_value;
 	set_value.Value = value1;
@@ -1915,10 +1933,6 @@ void Spawn::SetRequiredHistory(int32 event_id, int32 value1, int32 value2){
 	m_requiredHistory.releasewritelock(__FUNCTION__, __LINE__);
 }
 
-map<int32, vector<int16>* >* Spawn::GetQuestsRequired(){
-	return &required_quests;
-}
-
 void Spawn::SetTransporterID(int32 id){
 	transporter_id = id;
 }

+ 3 - 2
EQ2/source/WorldServer/Spawn.h

@@ -943,10 +943,10 @@ public:
 	bool	IsClientInMerchantLevelRange(Client* ent, bool sendMessageIfDenied = true);
 	int32	GetMerchantMinLevel();
 	int32	GetMerchantMaxLevel();
-	void	SetQuestsRequired(map<int32, vector<int16>* >* quests);
+	void	SetQuestsRequired(Spawn* new_spawn);
 	void	SetQuestsRequired(int32 quest_id, int16 quest_step);
+	bool	HasQuestsRequired();
 	void	SetRequiredHistory(int32 event_id, int32 value1, int32 value2);
-	map<int32, vector<int16>* >*	GetQuestsRequired();
 	void	SetTransporterID(int32 id);
 	int32	GetTransporterID();
 	bool	MeetsSpawnAccessRequirements(Player* player);
@@ -1132,6 +1132,7 @@ public:
 	void	SetSoundsDisabled(bool val) { disable_sounds = val; }
 protected:
 
+	bool	has_quests_required;
 	bool	send_spawn_changes;
 	bool	invulnerable;
 	bool	attack_resume_needed;

+ 1 - 1
EQ2/source/WorldServer/zoneserver.cpp

@@ -4044,7 +4044,7 @@ void ZoneServer::SendQuestUpdates(Client* client, Spawn* spawn){
 
 			if (spawn) {
 				spawn->m_requiredQuests.readlock(__FUNCTION__, __LINE__);
-				if (spawn && client->GetPlayer()->WasSentSpawn(spawn->GetID()) && !client->GetPlayer()->WasSpawnRemoved(spawn) && (client->GetPlayer()->CheckQuestRemoveFlag(spawn) || client->GetPlayer()->CheckQuestFlag(spawn) != 0 || (spawn->GetQuestsRequired()->size() > 0 && client->GetPlayer()->CheckQuestRequired(spawn))))
+				if (spawn && client->GetPlayer()->WasSentSpawn(spawn->GetID()) && !client->GetPlayer()->WasSpawnRemoved(spawn) && (client->GetPlayer()->CheckQuestRemoveFlag(spawn) || client->GetPlayer()->CheckQuestFlag(spawn) != 0 || (spawn->HasQuestsRequired() && client->GetPlayer()->CheckQuestRequired(spawn))))
 					SendSpawnChanges(spawn, client, false, true);
 				spawn->m_requiredQuests.releasereadlock(__FUNCTION__, __LINE__);
 			}