Browse Source

- Fixed house crash when you place an item and pick it up while the same zone instance is running
- Fixed cures not working correctly, it was checking the class while matching level requirements, it was checking the victim class, but we can't rely on the caster class being valid since /castspell among other customization options
- MSpellInfo Mutex updated to shared_mutex since there was a deadlock noticed before calling MSpellInfo.lock

Emagi 1 year ago
parent
commit
27c6eaa0fc

+ 3 - 14
EQ2/source/WorldServer/Entity.cpp

@@ -2226,7 +2226,6 @@ void Entity::CureDetrimentByType(int8 cure_count, int8 det_type, string cure_nam
 	int8 caster_class1 = 0;
 	int8 caster_class1 = 0;
 	int8 caster_class2 = 0;
 	int8 caster_class2 = 0;
 	int8 caster_class3 = 0;
 	int8 caster_class3 = 0;
-	int8 level_class = 0;
 	InfoStruct* info_struct = 0;
 	InfoStruct* info_struct = 0;
 	bool pass_level_check = false;
 	bool pass_level_check = false;
 
 
@@ -2236,16 +2235,12 @@ void Entity::CureDetrimentByType(int8 cure_count, int8 det_type, string cure_nam
 		if (det && det->det_type == det_type && !det->incurable){
 		if (det && det->det_type == det_type && !det->incurable){
 			levels = det->spell->spell->GetSpellLevels();
 			levels = det->spell->spell->GetSpellLevels();
 			info_struct = det->caster->GetInfoStruct();
 			info_struct = det->caster->GetInfoStruct();
-			caster_class1 = info_struct->get_class1();
-			caster_class2 = info_struct->get_class2();
-			caster_class3 = info_struct->get_class3();
 			pass_level_check = false;
 			pass_level_check = false;
 			bool has_level_checks = false;
 			bool has_level_checks = false;
 			for (int32 x = 0; x < levels->size(); x++){
 			for (int32 x = 0; x < levels->size(); x++){
 				has_level_checks = true;
 				has_level_checks = true;
-				level_class = levels->at(x)->adventure_class;
-				if (!cure_level || ((caster_class1 == level_class || caster_class2 == level_class || caster_class3 == level_class)
-					&& cure_level >= (levels->at(x)->spell_level / 10))){
+				// class checks are worthless we can't guarantee the caster is that class
+				if (!cure_level ||  cure_level >= (levels->at(x)->spell_level / 10)){
 					pass_level_check = true;
 					pass_level_check = true;
 					break;
 					break;
 				}
 				}
@@ -2283,7 +2278,6 @@ void Entity::CureDetrimentByControlEffect(int8 cure_count, int8 control_type, st
 	int8 caster_class1 = 0;
 	int8 caster_class1 = 0;
 	int8 caster_class2 = 0;
 	int8 caster_class2 = 0;
 	int8 caster_class3 = 0;
 	int8 caster_class3 = 0;
-	int8 level_class = 0;
 	InfoStruct* info_struct = 0;
 	InfoStruct* info_struct = 0;
 	bool pass_level_check = false;
 	bool pass_level_check = false;
 
 
@@ -2293,14 +2287,9 @@ void Entity::CureDetrimentByControlEffect(int8 cure_count, int8 control_type, st
 		if (det && det->control_effect == control_type && !det->incurable){
 		if (det && det->control_effect == control_type && !det->incurable){
 			levels = det->spell->spell->GetSpellLevels();
 			levels = det->spell->spell->GetSpellLevels();
 			info_struct = det->caster->GetInfoStruct();
 			info_struct = det->caster->GetInfoStruct();
-			caster_class1 = info_struct->get_class1();
-			caster_class2 = info_struct->get_class2();
-			caster_class3 = info_struct->get_class3();
 			pass_level_check = false;
 			pass_level_check = false;
 			for (int32 x = 0; x < levels->size(); x++){
 			for (int32 x = 0; x < levels->size(); x++){
-				level_class = levels->at(x)->adventure_class;
-				if (!cure_level || ((caster_class1 == level_class || caster_class2 == level_class || caster_class3 == level_class)
-					&& cure_level >= (levels->at(x)->spell_level / 10))){
+				if (!cure_level || cure_level >= (levels->at(x)->spell_level / 10)){
 					pass_level_check = true;
 					pass_level_check = true;
 					break;
 					break;
 				}
 				}

+ 13 - 26
EQ2/source/WorldServer/Spells.cpp

@@ -46,11 +46,11 @@ Spell::Spell(){
 	control_spell = false;
 	control_spell = false;
 	offense_spell = false;
 	offense_spell = false;
 	copied_spell = false;
 	copied_spell = false;
-	MSpellInfo.SetName("Spell::MSpellInfo");
 }
 }
 
 
 Spell::Spell(Spell* host_spell)
 Spell::Spell(Spell* host_spell)
 {
 {
+	std::shared_lock lock(host_spell->MSpellInfo);
 	copied_spell = true;
 	copied_spell = true;
 
 
 	spell = new SpellData;
 	spell = new SpellData;
@@ -155,7 +155,6 @@ Spell::Spell(Spell* host_spell)
 	control_spell = host_spell->IsControlSpell();
 	control_spell = host_spell->IsControlSpell();
 	offense_spell = host_spell->IsOffenseSpell();
 	offense_spell = host_spell->IsOffenseSpell();
 
 
-	host_spell->LockSpellInfo();
 	std::vector<LevelArray*>::iterator itr;
 	std::vector<LevelArray*>::iterator itr;
 	for (itr = host_spell->levels.begin(); itr != host_spell->levels.end(); itr++)
 	for (itr = host_spell->levels.begin(); itr != host_spell->levels.end(); itr++)
 	{
 	{
@@ -175,9 +174,6 @@ Spell::Spell(Spell* host_spell)
 		LUAData* data = *luaitr;
 		LUAData* data = *luaitr;
 		AddSpellLuaData(data->type, data->int_value, data->int_value2, data->float_value, data->float_value2, data->bool_value, string(data->string_value), string(data->string_value2), string(data->string_helper));
 		AddSpellLuaData(data->type, data->int_value, data->int_value2, data->float_value, data->float_value2, data->bool_value, string(data->string_value), string(data->string_value2), string(data->string_helper));
 	}
 	}
-	host_spell->UnlockSpellInfo();
-
-	MSpellInfo.SetName("Spell::MSpellInfo");
 }
 }
 
 
 Spell::Spell(SpellData* in_spell){
 Spell::Spell(SpellData* in_spell){
@@ -188,7 +184,6 @@ Spell::Spell(SpellData* in_spell){
 	control_spell = false;
 	control_spell = false;
 	offense_spell = false;
 	offense_spell = false;
 	copied_spell = false;
 	copied_spell = false;
-	MSpellInfo.SetName("Spell::MSpellInfo");
 }
 }
 
 
 Spell::~Spell(){
 Spell::~Spell(){
@@ -208,6 +203,7 @@ Spell::~Spell(){
 }
 }
 
 
 void Spell::AddSpellLuaData(int8 type, int int_value, int int_value2, float float_value, float float_value2, bool bool_value, string string_value, string string_value2, string helper){
 void Spell::AddSpellLuaData(int8 type, int int_value, int int_value2, float float_value, float float_value2, bool bool_value, string string_value, string string_value2, string helper){
+    std::unique_lock lock(MSpellInfo);
 	LUAData* data = new LUAData;
 	LUAData* data = new LUAData;
 	data->type = type;
 	data->type = type;
 	data->int_value = int_value;
 	data->int_value = int_value;
@@ -219,12 +215,11 @@ void Spell::AddSpellLuaData(int8 type, int int_value, int int_value2, float floa
 	data->string_value2 = string_value2;
 	data->string_value2 = string_value2;
 	data->string_helper = helper;
 	data->string_helper = helper;
 
 
-	MSpellInfo.lock();
 	lua_data.push_back(data);
 	lua_data.push_back(data);
-	MSpellInfo.unlock();
 }
 }
 
 
 void Spell::AddSpellLuaDataInt(int value, int value2, string helper) {
 void Spell::AddSpellLuaDataInt(int value, int value2, string helper) {
+	std::unique_lock lock(MSpellInfo);
 	LUAData *data = new LUAData;
 	LUAData *data = new LUAData;
 
 
 	data->type = 0;
 	data->type = 0;
@@ -235,12 +230,11 @@ void Spell::AddSpellLuaDataInt(int value, int value2, string helper) {
 	data->bool_value = false;
 	data->bool_value = false;
 	data->string_helper = helper;
 	data->string_helper = helper;
 
 
-	MSpellInfo.lock();
 	lua_data.push_back(data);
 	lua_data.push_back(data);
-	MSpellInfo.unlock();
 }
 }
 
 
 void Spell::AddSpellLuaDataFloat(float value, float value2, string helper) {
 void Spell::AddSpellLuaDataFloat(float value, float value2, string helper) {
+	std::unique_lock lock(MSpellInfo);
 	LUAData *data = new LUAData;
 	LUAData *data = new LUAData;
 
 
 	data->type = 1;
 	data->type = 1;
@@ -251,12 +245,11 @@ void Spell::AddSpellLuaDataFloat(float value, float value2, string helper) {
 	data->bool_value = false;
 	data->bool_value = false;
 	data->string_helper = helper;
 	data->string_helper = helper;
 
 
-	MSpellInfo.lock();
 	lua_data.push_back(data);
 	lua_data.push_back(data);
-	MSpellInfo.unlock();
 }
 }
 
 
 void Spell::AddSpellLuaDataBool(bool value, string helper) {
 void Spell::AddSpellLuaDataBool(bool value, string helper) {
+	std::unique_lock lock(MSpellInfo);
 	LUAData *data = new LUAData;
 	LUAData *data = new LUAData;
 
 
 	data->type = 2;
 	data->type = 2;
@@ -265,12 +258,11 @@ void Spell::AddSpellLuaDataBool(bool value, string helper) {
 	data->bool_value = value;
 	data->bool_value = value;
 	data->string_helper = helper;
 	data->string_helper = helper;
 
 
-	MSpellInfo.lock();
 	lua_data.push_back(data);
 	lua_data.push_back(data);
-	MSpellInfo.unlock();
 }
 }
 
 
 void Spell::AddSpellLuaDataString(string value, string value2,string helper) {
 void Spell::AddSpellLuaDataString(string value, string value2,string helper) {
+	std::unique_lock lock(MSpellInfo);
 	LUAData *data = new LUAData;
 	LUAData *data = new LUAData;
 
 
 	data->type = 3;
 	data->type = 3;
@@ -283,9 +275,7 @@ void Spell::AddSpellLuaDataString(string value, string value2,string helper) {
 	data->string_value2 = value2;
 	data->string_value2 = value2;
 	data->string_helper = helper;
 	data->string_helper = helper;
 
 
-	MSpellInfo.lock();
 	lua_data.push_back(data);
 	lua_data.push_back(data);
-	MSpellInfo.unlock();
 }
 }
 
 
 int16 Spell::GetLevelRequired(Player* player){
 int16 Spell::GetLevelRequired(Player* player){
@@ -1217,13 +1207,13 @@ EQ2Packet* Spell::SerializeSpell(Client* client, bool display, bool trait_displa
 }
 }
 
 
 void Spell::AddSpellEffect(int8 percentage, int8 subbullet, string description){
 void Spell::AddSpellEffect(int8 percentage, int8 subbullet, string description){
+	std::unique_lock lock(MSpellInfo);
 	SpellDisplayEffect* effect = new SpellDisplayEffect;
 	SpellDisplayEffect* effect = new SpellDisplayEffect;
 	effect->description = description;
 	effect->description = description;
 	effect->subbullet = subbullet;
 	effect->subbullet = subbullet;
 	effect->percentage = percentage;
 	effect->percentage = percentage;
-	MSpellInfo.lock();
+	
 	effects.push_back(effect);
 	effects.push_back(effect);
-	MSpellInfo.unlock();
 }
 }
 
 
 int16 Spell::GetHPRequired(Spawn* spawn){
 int16 Spell::GetHPRequired(Spawn* spawn){
@@ -1336,13 +1326,13 @@ const char* Spell::GetDescription(){
 }
 }
 
 
 void Spell::AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level){
 void Spell::AddSpellLevel(int8 adventure_class, int8 tradeskill_class, int16 level){
+	std::unique_lock lock(MSpellInfo);
 	LevelArray* lvl = new LevelArray;
 	LevelArray* lvl = new LevelArray;
 	lvl->adventure_class = adventure_class;
 	lvl->adventure_class = adventure_class;
 	lvl->tradeskill_class = tradeskill_class;
 	lvl->tradeskill_class = tradeskill_class;
 	lvl->spell_level = level;
 	lvl->spell_level = level;
-	MSpellInfo.lock();
+	
 	levels.push_back(lvl);
 	levels.push_back(lvl);
-	MSpellInfo.unlock();
 }
 }
 
 
 int32 Spell::GetSpellID(){
 int32 Spell::GetSpellID(){
@@ -2190,23 +2180,21 @@ void Spell::ModifyCastTime(Entity* caster){
 }
 }
 
 
 vector <SpellDisplayEffect*>* Spell::GetSpellEffects(){
 vector <SpellDisplayEffect*>* Spell::GetSpellEffects(){
-	MSpellInfo.lock();
+	std::shared_lock lock(MSpellInfo);
 	vector <SpellDisplayEffect*>* ret = &effects;
 	vector <SpellDisplayEffect*>* ret = &effects;
-	MSpellInfo.unlock();
 	return ret;
 	return ret;
 }
 }
 
 
 vector <LevelArray*>* Spell::GetSpellLevels(){
 vector <LevelArray*>* Spell::GetSpellLevels(){
-	MSpellInfo.lock();
+	std::shared_lock lock(MSpellInfo);
 	vector <LevelArray*>* ret = &levels;
 	vector <LevelArray*>* ret = &levels;
-	MSpellInfo.unlock();
 	return ret;
 	return ret;
 }
 }
 
 
 bool Spell::ScribeAllowed(Player* player){
 bool Spell::ScribeAllowed(Player* player){
+	std::shared_lock lock(MSpellInfo);
 	bool ret = false;
 	bool ret = false;
 	if(player){
 	if(player){
-		MSpellInfo.lock();
 		for(int32 i=0;!ret && i<levels.size();i++){
 		for(int32 i=0;!ret && i<levels.size();i++){
 			int16 mylevel = player->GetLevel();
 			int16 mylevel = player->GetLevel();
 			int16 spelllevels = levels[i]->spell_level;
 			int16 spelllevels = levels[i]->spell_level;
@@ -2216,7 +2204,6 @@ bool Spell::ScribeAllowed(Player* player){
 			if((player->GetAdventureClass() == levels[i]->adventure_class || player->GetTradeskillClass() == levels[i]->tradeskill_class) && player->GetLevel() >= levels[i]->spell_level/10)
 			if((player->GetAdventureClass() == levels[i]->adventure_class || player->GetTradeskillClass() == levels[i]->tradeskill_class) && player->GetLevel() >= levels[i]->spell_level/10)
 				ret = true;
 				ret = true;
 		}
 		}
-		MSpellInfo.unlock();
 	}
 	}
 	return ret;
 	return ret;
 }
 }

+ 4 - 4
EQ2/source/WorldServer/Spells.h

@@ -21,6 +21,8 @@
 #define __EQ2_SPELLS__
 #define __EQ2_SPELLS__
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
+#include <mutex>
+#include <shared_mutex>
 #include "../common/types.h"
 #include "../common/types.h"
 #include "../common/EQPacket.h"
 #include "../common/EQPacket.h"
 #include "../common/MiscFunctions.h"
 #include "../common/MiscFunctions.h"
@@ -349,9 +351,8 @@ public:
 
 
 	vector<SpellDisplayEffect*> effects;
 	vector<SpellDisplayEffect*> effects;
 	vector<LUAData*> lua_data;
 	vector<LUAData*> lua_data;
-
-	void LockSpellInfo() { MSpellInfo.lock(); }
-	void UnlockSpellInfo() { MSpellInfo.unlock(); }
+	
+	mutable std::shared_mutex MSpellInfo;
 private:
 private:
 	bool stay_locked = false;
 	bool stay_locked = false;
 	bool heal_spell;
 	bool heal_spell;
@@ -365,7 +366,6 @@ private:
 	
 	
 	//vector<SpellDisplayEffect*> effects;
 	//vector<SpellDisplayEffect*> effects;
 	vector <LevelArray*> levels;
 	vector <LevelArray*> levels;
-	Mutex MSpellInfo;
 };
 };
 class MasterSpellList{
 class MasterSpellList{
 public:
 public:

+ 2 - 1
EQ2/source/WorldServer/client.cpp

@@ -10664,7 +10664,8 @@ bool Client::PopulateHouseSpawn(PacketStruct* place_object)
 		if (!spawnDBID)
 		if (!spawnDBID)
 		{
 		{
 			GetCurrentZone()->house_object_database_lookup.Put(tmp->GetModelType(), tmp->GetDatabaseID());
 			GetCurrentZone()->house_object_database_lookup.Put(tmp->GetModelType(), tmp->GetDatabaseID());
-			GetCurrentZone()->AddObject(tmp->GetDatabaseID(), (Object*)tmp);
+			// we need to copy as to not delete the ZoneServer object_list entry this on house item pickup
+			GetCurrentZone()->AddObject(tmp->GetDatabaseID(), ((Object*)tmp)->Copy()); 
 		}
 		}
 
 
 		return true;
 		return true;