Browse Source

Protection to group members and also heroic opportunities (avoid crashes)

Fix #185
image 3 years ago
parent
commit
7ae7d637a3

+ 52 - 32
EQ2/source/WorldServer/Bots/Bot.cpp

@@ -300,20 +300,27 @@ Spell* Bot::GetHealSpell() {
 	// There was a heal spell so find a group member that needs healing
 	int8 threshold = GetHealThreshold();
 	GroupMemberInfo* gmi = GetGroupMemberInfo();
-	deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-	for (int8 i = 0; i < members->size(); i++) {
-		Entity* member = members->at(i)->member;
-
-		if (!member->Alive())
-			continue;
+	PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+	if (group)
+	{
+		group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+		deque<GroupMemberInfo*>* members = group->GetMembers();
+		for (int8 i = 0; i < members->size(); i++) {
+			Entity* member = members->at(i)->member;
+
+			if (!member->Alive())
+				continue;
 
-		int8 percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
-		if (percent <= threshold) {
-			if (spell) {
-				SetTarget(member);
-				return spell;
+			int8 percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
+			if (percent <= threshold) {
+				if (spell) {
+					SetTarget(member);
+					group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
+					return spell;
+				}
 			}
 		}
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 
 
@@ -384,19 +391,26 @@ Spell* Bot::GetHoTWardSpell() {
 	// There was a spell so find a group member that needs healing
 	int8 threshold = GetHealThreshold();
 	GroupMemberInfo* gmi = GetGroupMemberInfo();
-	deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-	for (int8 i = 0; i < members->size(); i++) {
-		Entity* member = members->at(i)->member;
-		int8 percent = 0;
-		if (member->GetHP() > 0)
-			percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
-
-		if (percent <= 99 && percent > threshold) {
-			if (spell) {
-				SetTarget(member);
-				return spell;
+	PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+	if (group)
+	{
+		group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+		deque<GroupMemberInfo*>* members = group->GetMembers();
+		for (int8 i = 0; i < members->size(); i++) {
+			Entity* member = members->at(i)->member;
+			int8 percent = 0;
+			if (member->GetHP() > 0)
+				percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
+
+			if (percent <= 99 && percent > threshold) {
+				if (spell) {
+					SetTarget(member);
+					group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
+					return spell;
+				}
 			}
 		}
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 
 	return 0;
@@ -489,17 +503,23 @@ Spell* Bot::GetRezSpell() {
 		return 0;
 
 	Entity* target = 0;
-	deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-	for (int8 i = 0; i < members->size(); i++) {
-		Entity* member = members->at(i)->member;
-		if (member && !member->Alive() && member->IsPlayer()) {
-			PendingResurrection* rez = members->at(i)->client->GetCurrentRez();
-			if (rez->active)
-				continue;
-
-			target = member;
-			break;
+	PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+	if (group)
+	{
+		group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+		deque<GroupMemberInfo*>* members = group->GetMembers();
+		for (int8 i = 0; i < members->size(); i++) {
+			Entity* member = members->at(i)->member;
+			if (member && !member->Alive() && member->IsPlayer()) {
+				PendingResurrection* rez = members->at(i)->client->GetCurrentRez();
+				if (rez->active)
+					continue;
+
+				target = member;
+				break;
+			}
 		}
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 
 	if (!target)

+ 38 - 20
EQ2/source/WorldServer/Bots/BotCommands.cpp

@@ -40,12 +40,18 @@ void Commands::Command_Bot(Client* client, Seperator* sep) {
 					if (client->GetPlayer()->AttackAllowed(target)) {
 						GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
 						if (gmi) {
-							deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-							deque<GroupMemberInfo*>::iterator itr;
-							for (itr = members->begin(); itr != members->end(); itr++) {
-								if ((*itr)->member->IsBot() && ((Bot*)(*itr)->member)->GetOwner() == client->GetPlayer()) {
-									((Bot*)(*itr)->member)->SetCombatTarget(target->GetID());
+							PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+							if (group)
+							{
+								group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+								deque<GroupMemberInfo*>* members = group->GetMembers();
+								deque<GroupMemberInfo*>::iterator itr;
+								for (itr = members->begin(); itr != members->end(); itr++) {
+									if ((*itr)->member->IsBot() && ((Bot*)(*itr)->member)->GetOwner() == client->GetPlayer()) {
+										((Bot*)(*itr)->member)->SetCombatTarget(target->GetID());
+									}
 								}
+								group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 							}
 						}
 					}
@@ -97,13 +103,19 @@ void Commands::Command_Bot(Client* client, Seperator* sep) {
 				return;
 			}
 
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-			for (int8 i = 0; i < members->size(); i++) {
-				GroupMemberInfo* gmi2 = members->at(i);
-				if (gmi2->member->IsBot() && ((Bot*)gmi2->member)->GetOwner() == client->GetPlayer()) {
-					((Bot*)gmi2->member)->SetMainTank(target);
-					client->Message(CHANNEL_COMMAND_TEXT, "Setting main tank for %s to %s", gmi2->member->GetName(), target->GetName());
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				for (int8 i = 0; i < members->size(); i++) {
+					GroupMemberInfo* gmi2 = members->at(i);
+					if (gmi2->member->IsBot() && ((Bot*)gmi2->member)->GetOwner() == client->GetPlayer()) {
+						((Bot*)gmi2->member)->SetMainTank(target);
+						client->Message(CHANNEL_COMMAND_TEXT, "Setting main tank for %s to %s", gmi2->member->GetName(), target->GetName());
+					}
 				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 			return;
 		}
@@ -132,16 +144,22 @@ void Commands::Command_Bot(Client* client, Seperator* sep) {
 				GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
 				if (gmi) {
 					Player* player = client->GetPlayer();
-					deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-					for (int8 i = 0; i < members->size(); i++) {
-						Entity* member = members->at(i)->member;
-						if (member->IsBot() && ((Bot*)member)->GetOwner() == player) {
-							member->appearance.pos.grid_id = player->appearance.pos.grid_id;
-							member->SetX(player->GetX());
-							member->SetY(player->GetY());
-							member->SetZ(player->GetZ());
-							client->Message(CHANNEL_COLOR_YELLOW, "Summoning %s.", member->GetName());
+					PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+					if (group)
+					{
+						group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+						deque<GroupMemberInfo*>* members = group->GetMembers();
+						for (int8 i = 0; i < members->size(); i++) {
+							Entity* member = members->at(i)->member;
+							if (member->IsBot() && ((Bot*)member)->GetOwner() == player) {
+								member->appearance.pos.grid_id = player->appearance.pos.grid_id;
+								member->SetX(player->GetX());
+								member->SetY(player->GetY());
+								member->SetZ(player->GetZ());
+								client->Message(CHANNEL_COLOR_YELLOW, "Summoning %s.", member->GetName());
+							}
 						}
+						group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 					}
 					return;
 				}

+ 14 - 8
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -4731,15 +4731,21 @@ void Commands::Command_Follow(Client* client, Seperator* sep)
 
 		world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
-		deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-		// Loop through the group members
-		for (itr = members->begin(); itr != members->end(); itr++) {
-			// If a group member matches a target
-			if ((*itr)->member == client->GetPlayer()->GetTarget()) {
-				// toggle the flag and break the loop
-				targetInGroup = true;
-				break;
+		PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+		if (group)
+		{
+			group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+			deque<GroupMemberInfo*>* members = group->GetMembers();
+			// Loop through the group members
+			for (itr = members->begin(); itr != members->end(); itr++) {
+				// If a group member matches a target
+				if ((*itr)->member == client->GetPlayer()->GetTarget()) {
+					// toggle the flag and break the loop
+					targetInGroup = true;
+					break;
+				}
 			}
+			group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 		}
 
 		world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);

+ 29 - 23
EQ2/source/WorldServer/Guilds/Guild.cpp

@@ -1059,35 +1059,41 @@ bool Guild::AddPointsToGroup(Client *client, float points, const char *comment,
 
 	mMembers.readlock(__FUNCTION__, __LINE__);
 	world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
-	
-	group_members = world.GetGroupManager()->GetGroupMembers(client->GetPlayer()->GetGroupMemberInfo()->group_id);
-	for (itr = group_members->begin(); itr != group_members->end(); itr++) {
-		gmi = *itr;
 
-		if (!gmi->client)
-			continue;
+	PlayerGroup* group = world.GetGroupManager()->GetGroup(client->GetPlayer()->GetGroupMemberInfo()->group_id);
+	if (group)
+	{
+		group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+		deque<GroupMemberInfo*>* group_members = group->GetMembers();
+		for (itr = group_members->begin(); itr != group_members->end(); itr++) {
+			gmi = *itr;
 
-		if (gmi->client->GetPlayer()->GetGuild() != this) {
-			LogWrite(GUILD__DEBUG, 0, "Guilds", "PlayerID: %i not in guild to receive group points! Skipping...", gmi->client->GetPlayer()->GetCharacterID());
-			continue;
-		}
+			if (!gmi->client)
+				continue;
 
-		if (!(gm = members[gmi->client->GetCharacterID()]) || !permissions.Get(gm->rank)->Get(GUILD_PERMISSIONS_RECEIVE_POINTS)) {
-			LogWrite(GUILD__DEBUG, 0, "Guilds", "PlayerID: %i not allowed to receive points! Skipping...", gm->character_id);
-			continue;
-		}
+			if (gmi->client->GetPlayer()->GetGuild() != this) {
+				LogWrite(GUILD__DEBUG, 0, "Guilds", "PlayerID: %i not in guild to receive group points! Skipping...", gmi->client->GetPlayer()->GetCharacterID());
+				continue;
+			}
 
-		gm->points += points;
-		character_ids.push_back(gm->character_id);
+			if (!(gm = members[gmi->client->GetCharacterID()]) || !permissions.Get(gm->rank)->Get(GUILD_PERMISSIONS_RECEIVE_POINTS)) {
+				LogWrite(GUILD__DEBUG, 0, "Guilds", "PlayerID: %i not allowed to receive points! Skipping...", gm->character_id);
+				continue;
+			}
 
-		AddPointHistory(gm, Timer::GetUnixTimeStamp(), client->GetPlayer()->GetName(), points, comment);
-		gmi->client->Message(CHANNEL_COLOR_GUILD_MSGS, "%s increased your guild member points by %.1f.", client->GetPlayer()->GetName(), points);
-		LogWrite(GUILD__DEBUG, 0, "Guilds", "Guild: %s", GetName());
-		LogWrite(GUILD__DEBUG, 0, "Guilds", "\tAwarded By: %s +%.1f pts to Player: %s", client->GetPlayer()->GetName(), points, gm->name);
+			gm->points += points;
+			character_ids.push_back(gm->character_id);
 
-		LogWrite(MISC__TODO, 1, "TODO", "Comment that this is temporary?\n%s, %s, %i", __FILE__, __FUNCTION__, __LINE__);
-		SendGuildMember(gm); //tmp
+			AddPointHistory(gm, Timer::GetUnixTimeStamp(), client->GetPlayer()->GetName(), points, comment);
+			gmi->client->Message(CHANNEL_COLOR_GUILD_MSGS, "%s increased your guild member points by %.1f.", client->GetPlayer()->GetName(), points);
+			LogWrite(GUILD__DEBUG, 0, "Guilds", "Guild: %s", GetName());
+			LogWrite(GUILD__DEBUG, 0, "Guilds", "\tAwarded By: %s +%.1f pts to Player: %s", client->GetPlayer()->GetName(), points, gm->name);
 
+			LogWrite(MISC__TODO, 1, "TODO", "Comment that this is temporary?\n%s, %s, %i", __FILE__, __FUNCTION__, __LINE__);
+			SendGuildMember(gm); //tmp
+
+		}
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 
 	world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -1342,7 +1348,7 @@ void Guild::AddGuildEvent(int64 event_id, int32 type, const char *description, i
 	GuildEvent *ge;
 
 	assert(description);
-	assert(event_filters.Get(type)->Get(GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY));
+//	assert(event_filters.Get(type)->Get(GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY));
 	assert(guild_events.size() < GUILD_MAX_EVENTS);
 
 	ge = new GuildEvent;

+ 22 - 10
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -3926,12 +3926,18 @@ int EQ2Emu_lua_GetGroup(lua_State* state) {
 		world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 		deque<GroupMemberInfo*>::iterator itr;
-		deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Player*)spawn)->GetGroupMemberInfo()->group_id);
-		GroupMemberInfo* info = 0;
-		for (itr = members->begin(); itr != members->end(); itr++) {
-			info = *itr;
-			if (info->client)
-				groupMembers.push_back(info->client->GetPlayer());
+		PlayerGroup* group = world.GetGroupManager()->GetGroup(((Player*)spawn)->GetGroupMemberInfo()->group_id);
+		if (group)
+		{
+			group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+			deque<GroupMemberInfo*>* members = group->GetMembers();
+			GroupMemberInfo* info = 0;
+			for (itr = members->begin(); itr != members->end(); itr++) {
+				info = *itr;
+				if (info->client)
+					groupMembers.push_back(info->client->GetPlayer());
+			}
+			group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 		}
 
 		world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -7681,10 +7687,16 @@ int EQ2Emu_lua_StartHeroicOpportunity(lua_State* state) {
 				world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 				deque<GroupMemberInfo*>::iterator itr;
-				deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Entity*)caster)->GetGroupMemberInfo()->group_id);
-				for (itr = members->begin(); itr != members->end(); itr++) {
-					if ((*itr)->client)
-						ClientPacketFunctions::SendHeroicOPUpdate((*itr)->client, ho);
+				PlayerGroup* group = world.GetGroupManager()->GetGroup(((Entity*)caster)->GetGroupMemberInfo()->group_id);
+				if (group)
+				{
+					group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+					deque<GroupMemberInfo*>* members = group->GetMembers();
+					for (itr = members->begin(); itr != members->end(); itr++) {
+						if ((*itr)->client)
+							ClientPacketFunctions::SendHeroicOPUpdate((*itr)->client, ho);
+					}
+					group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 				}
 
 				world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);

+ 12 - 6
EQ2/source/WorldServer/NPC_AI.cpp

@@ -395,13 +395,19 @@ void Brain::AddToEncounter(Entity* entity) {
 		world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 		deque<GroupMemberInfo*>::iterator itr;
-		deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(group_id);
-		for (itr = members->begin(); itr != members->end(); itr++) {
-			if ((*itr)->client)
-			{
-				m_encounter.push_back((*itr)->client->GetPlayer()->GetID());
-				m_encounter_playerlist.insert(make_pair((*itr)->client->GetPlayer()->GetCharacterID(), (*itr)->client->GetPlayer()->GetID()));
+		PlayerGroup* group = world.GetGroupManager()->GetGroup(group_id);
+		if (group)
+		{
+			group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+			deque<GroupMemberInfo*>* members = group->GetMembers();
+			for (itr = members->begin(); itr != members->end(); itr++) {
+				if ((*itr)->client)
+				{
+					m_encounter.push_back((*itr)->client->GetPlayer()->GetID());
+					m_encounter_playerlist.insert(make_pair((*itr)->client->GetPlayer()->GetCharacterID(), (*itr)->client->GetPlayer()->GetID()));
+				}
 			}
+			group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 		}
 
 		world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);

+ 97 - 77
EQ2/source/WorldServer/Player.cpp

@@ -148,10 +148,13 @@ Player::~Player(){
 		}
 	}
 
+	mLUAHistory.writelock();
 	map<int32, LUAHistory*>::iterator itr4;
 	for (itr4 = m_charLuaHistory.begin(); itr4 != m_charLuaHistory.end(); itr4++) {
 		safe_delete(itr4->second);
 	}
+	m_charLuaHistory.clear();
+	mLUAHistory.releasewritelock();
 
 	safe_delete_array(movement_packet);
 	safe_delete_array(old_movement_packet);
@@ -4824,95 +4827,101 @@ void Player::SetGroupInformation(PacketStruct* packet){
 
 	world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 	if (GetGroupMemberInfo()) {
-		deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(GetGroupMemberInfo()->group_id);
-		deque<GroupMemberInfo*>::iterator itr;
-		GroupMemberInfo* info = 0;
-		int x = 0;
+		PlayerGroup* group = world.GetGroupManager()->GetGroup(GetGroupMemberInfo()->group_id);
+		if (group)
+		{
+			group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+			deque<GroupMemberInfo*>* members = group->GetMembers();
+			deque<GroupMemberInfo*>::iterator itr;
+			GroupMemberInfo* info = 0;
+			int x = 0;
 
-		for (itr = members->begin(); itr != members->end(); itr++) {
-			info = *itr;
+			for (itr = members->begin(); itr != members->end(); itr++) {
+				info = *itr;
 
-			if (info == GetGroupMemberInfo()) {
-				if (info->leader)
-					packet->setDataByName("group_leader_id", 0xFFFFFFFF);	// If this player is the group leader then fill this element with FF FF FF FF
+				if (info == GetGroupMemberInfo()) {
+					if (info->leader)
+						packet->setDataByName("group_leader_id", 0xFFFFFFFF);	// If this player is the group leader then fill this element with FF FF FF FF
 
-				continue;
-			}
-			else {
-				if (info->leader)
-					packet->setDataByName("group_leader_id", x);			// If leader is some one else then fill with the slot number they are in
-			}
+					continue;
+				}
+				else {
+					if (info->leader)
+						packet->setDataByName("group_leader_id", x);			// If leader is some one else then fill with the slot number they are in
+				}
 
-			member = info->member;
+				member = info->member;
 
-			if (member && member->GetZone() == GetZone()) {
-				packet->setSubstructDataByName("group_members", "unknown3", 1, x);
-				packet->setSubstructDataByName("group_members", "spawn_id", GetIDWithPlayerSpawn(member), x);
-				
-				if (member->HasPet()) {
-					if (member->GetPet())
-						packet->setSubstructDataByName("group_members", "pet_id", GetIDWithPlayerSpawn(member->GetPet()), x);
+				if (member && member->GetZone() == GetZone()) {
+					packet->setSubstructDataByName("group_members", "unknown3", 1, x);
+					packet->setSubstructDataByName("group_members", "spawn_id", GetIDWithPlayerSpawn(member), x);
+
+					if (member->HasPet()) {
+						if (member->GetPet())
+							packet->setSubstructDataByName("group_members", "pet_id", GetIDWithPlayerSpawn(member->GetPet()), x);
+						else
+							packet->setSubstructDataByName("group_members", "pet_id", GetIDWithPlayerSpawn(member->GetCharmedPet()), x);
+					}
 					else
-						packet->setSubstructDataByName("group_members", "pet_id", GetIDWithPlayerSpawn(member->GetCharmedPet()), x);
-				}
-				else
-					packet->setSubstructDataByName("group_members", "pet_id", 0xFFFFFFFF, x);
+						packet->setSubstructDataByName("group_members", "pet_id", 0xFFFFFFFF, x);
 
-				//Send detriment counts as 255 if all dets of that type are incurable
-				det_count = member->GetTraumaCount();
-				if (det_count > 0) {
-					if(!member->HasCurableDetrimentType(DET_TYPE_TRAUMA))
-						det_count = 255;
-				}
-				packet->setSubstructDataByName("group_members", "trauma_count", det_count, x);
+					//Send detriment counts as 255 if all dets of that type are incurable
+					det_count = member->GetTraumaCount();
+					if (det_count > 0) {
+						if (!member->HasCurableDetrimentType(DET_TYPE_TRAUMA))
+							det_count = 255;
+					}
+					packet->setSubstructDataByName("group_members", "trauma_count", det_count, x);
 
-				det_count = member->GetArcaneCount();
-				if (det_count > 0) {
-					if (!member->HasCurableDetrimentType(DET_TYPE_ARCANE))
-						det_count = 255;
-				}
-				packet->setSubstructDataByName("group_members", "arcane_count", det_count, x);
+					det_count = member->GetArcaneCount();
+					if (det_count > 0) {
+						if (!member->HasCurableDetrimentType(DET_TYPE_ARCANE))
+							det_count = 255;
+					}
+					packet->setSubstructDataByName("group_members", "arcane_count", det_count, x);
 
-				det_count = member->GetNoxiousCount();
-				if (det_count > 0) {
-					if (!member->HasCurableDetrimentType(DET_TYPE_NOXIOUS))
-						det_count = 255;
-				}
-				packet->setSubstructDataByName("group_members", "noxious_count", det_count, x);
+					det_count = member->GetNoxiousCount();
+					if (det_count > 0) {
+						if (!member->HasCurableDetrimentType(DET_TYPE_NOXIOUS))
+							det_count = 255;
+					}
+					packet->setSubstructDataByName("group_members", "noxious_count", det_count, x);
 
-				det_count = member->GetElementalCount();
-				if (det_count > 0) {
-					if (!member->HasCurableDetrimentType(DET_TYPE_ELEMENTAL))
-						det_count = 255;
-				}
-				packet->setSubstructDataByName("group_members", "elemental_count", det_count, x);
+					det_count = member->GetElementalCount();
+					if (det_count > 0) {
+						if (!member->HasCurableDetrimentType(DET_TYPE_ELEMENTAL))
+							det_count = 255;
+					}
+					packet->setSubstructDataByName("group_members", "elemental_count", det_count, x);
 
-				det_count = member->GetCurseCount();
-				if (det_count > 0) {
-					if (!member->HasCurableDetrimentType(DET_TYPE_CURSE))
-						det_count = 255;
+					det_count = member->GetCurseCount();
+					if (det_count > 0) {
+						if (!member->HasCurableDetrimentType(DET_TYPE_CURSE))
+							det_count = 255;
+					}
+					packet->setSubstructDataByName("group_members", "curse_count", det_count, x);
+				}
+				else {
+					packet->setSubstructDataByName("group_members", "unknown3", 2, x);
+					packet->setSubstructDataByName("group_members", "pet_id", 0xFFFFFFFF, x);
+					//packet->setSubstructDataByName("group_members", "unknown5", 1, x, 1); // unknown5 > 1 = name is blue
 				}
-				packet->setSubstructDataByName("group_members", "curse_count", det_count, x);
-			}
-			else {
-				packet->setSubstructDataByName("group_members", "unknown3", 2, x);
-				packet->setSubstructDataByName("group_members", "pet_id", 0xFFFFFFFF, x);
-				//packet->setSubstructDataByName("group_members", "unknown5", 1, x, 1); // unknown5 > 1 = name is blue
-			}
-
-			packet->setSubstructDataByName("group_members", "name", info->name.c_str(), x);
-			packet->setSubstructDataByName("group_members", "hp_current", info->hp_current, x);
-			packet->setSubstructDataByName("group_members", "hp_max", info->hp_max, x);
-			packet->setSubstructDataByName("group_members", "power_current", info->power_current, x);
-			packet->setSubstructDataByName("group_members", "power_max", info->power_max, x);
-			packet->setSubstructDataByName("group_members", "level_current", info->level_current, x);
-			packet->setSubstructDataByName("group_members", "level_max", info->level_max, x);
-			packet->setSubstructDataByName("group_members", "zone", info->zone.c_str(), x);
-			packet->setSubstructDataByName("group_members", "race_id", info->race_id, x);
-			packet->setSubstructDataByName("group_members", "class_id", info->class_id, x);
 
-			x++;
+				packet->setSubstructDataByName("group_members", "name", info->name.c_str(), x);
+				packet->setSubstructDataByName("group_members", "hp_current", info->hp_current, x);
+				packet->setSubstructDataByName("group_members", "hp_max", info->hp_max, x);
+				packet->setSubstructDataByName("group_members", "power_current", info->power_current, x);
+				packet->setSubstructDataByName("group_members", "power_max", info->power_max, x);
+				packet->setSubstructDataByName("group_members", "level_current", info->level_current, x);
+				packet->setSubstructDataByName("group_members", "level_max", info->level_max, x);
+				packet->setSubstructDataByName("group_members", "zone", info->zone.c_str(), x);
+				packet->setSubstructDataByName("group_members", "race_id", info->race_id, x);
+				packet->setSubstructDataByName("group_members", "class_id", info->class_id, x);
+
+				x++;
+			}
 		}
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 	//packet->PrintPacket();
 	world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -5878,16 +5887,20 @@ void Player::SendControlFlagUpdates(Client* client){
 }
 
 void Player::LoadLUAHistory(int32 event_id, LUAHistory* history) {
+	mLUAHistory.writelock();
 	if (m_charLuaHistory.count(event_id) > 0) {
 		LogWrite(PLAYER__ERROR, 0, "Player", "Attempted to added a dupicate event (%u) to character LUA history", event_id);
 		safe_delete(history);
+		mLUAHistory.releasewritelock();
 		return;
 	}
 
-	m_charLuaHistory[event_id] = history;
+	m_charLuaHistory.insert(make_pair(event_id,history));
+	mLUAHistory.releasewritelock();
 }
 
 void Player::SaveLUAHistory() {
+	mLUAHistory.readlock();
 	LogWrite(PLAYER__DEBUG, 0, "Player", "Saving LUA History for Player: '%s'", GetName());
 
 	map<int32, LUAHistory*>::iterator itr;
@@ -5897,30 +5910,37 @@ void Player::SaveLUAHistory() {
 			itr->second->SaveNeeded = false;
 		}
 	}
+	mLUAHistory.releasereadlock();
 }
 
 void Player::UpdateLUAHistory(int32 event_id, int32 value, int32 value2) {
+	mLUAHistory.writelock();
 	LUAHistory* hd = 0;
 
 	if (m_charLuaHistory.count(event_id) > 0)
 		hd = m_charLuaHistory[event_id];
 	else {
 		hd = new LUAHistory;
-		m_charLuaHistory[event_id] = hd;
+		m_charLuaHistory.insert(make_pair(event_id,hd));
 	}
 
 	hd->Value = value;
 	hd->Value2 = value2;
 	hd->SaveNeeded = true;
 	SendHistoryRequiredSpawns(event_id);
+	mLUAHistory.releasewritelock();
 }
 
 LUAHistory* Player::GetLUAHistory(int32 event_id) {
 	LUAHistory* ret = 0;
 
+	mLUAHistory.readlock();
+
 	if (m_charLuaHistory.count(event_id) > 0)
 		ret = m_charLuaHistory[event_id];
 
+	mLUAHistory.releasereadlock();
+
 	return ret;
 }
 

+ 1 - 0
EQ2/source/WorldServer/Player.h

@@ -1007,6 +1007,7 @@ private:
 	map<int8, map<int8, vector<HistoryData*> > > m_characterHistory;
 
 	map<int32, LUAHistory*> m_charLuaHistory;
+	Mutex mLUAHistory;
 
 	int32 tmp_mount_model;
 	EQ2_Color tmp_mount_color;

+ 14 - 21
EQ2/source/WorldServer/PlayerGroups.cpp

@@ -124,40 +124,40 @@ void PlayerGroup::Disband() {
 
 void PlayerGroup::SendGroupUpdate(Client* exclude) {
 	deque<GroupMemberInfo*>::iterator itr;
-	MGroupMembers.readlock();
+	MGroupMembers.readlock(__FUNCTION__, __LINE__);
 	for (itr = m_members.begin(); itr != m_members.end(); itr++) {
 		GroupMemberInfo* gmi = *itr;
 		if (gmi->client && gmi->client != exclude && !gmi->client->IsZoning())
 			gmi->client->GetPlayer()->SetCharSheetChanged(true);
 	}
-	MGroupMembers.releasereadlock();
+	MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 }
 
 void PlayerGroup::SimpleGroupMessage(const char* message) {
 	deque<GroupMemberInfo*>::iterator itr;
-	MGroupMembers.readlock();
+	MGroupMembers.readlock(__FUNCTION__, __LINE__);
 	for(itr = m_members.begin(); itr != m_members.end(); itr++) {
 		GroupMemberInfo* info = *itr;
 		if(info->client)
 			info->client->SimpleMessage(CHANNEL_GROUP, message);
 	}
-	MGroupMembers.releasereadlock();
+	MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 }
 
 void PlayerGroup::GroupChatMessage(Spawn* from, const char* message) {
 	deque<GroupMemberInfo*>::iterator itr;
-	MGroupMembers.readlock();
+	MGroupMembers.readlock(__FUNCTION__, __LINE__);
 	for(itr = m_members.begin(); itr != m_members.end(); itr++) {
 		GroupMemberInfo* info = *itr;
 		if(info && info->client && info->client->GetCurrentZone())
 			info->client->GetCurrentZone()->HandleChatMessage(info->client, from, 0, CHANNEL_GROUP_SAY, message, 0);
 	}
-	MGroupMembers.releasereadlock();
+	MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 }
 
 void PlayerGroup::MakeLeader(Entity* new_leader) {
 	deque<GroupMemberInfo*>::iterator itr;
-	MGroupMembers.readlock();
+	MGroupMembers.readlock(__FUNCTION__, __LINE__);
 	for (itr = m_members.begin(); itr != m_members.end(); itr++) {
 		GroupMemberInfo* info = *itr;
 		if (info->leader) {
@@ -165,7 +165,7 @@ void PlayerGroup::MakeLeader(Entity* new_leader) {
 			break;
 		}
 	}
-	MGroupMembers.releasereadlock();
+	MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 
 	new_leader->GetGroupMemberInfo()->leader = true;
 	SendGroupUpdate();
@@ -412,13 +412,6 @@ PlayerGroup* PlayerGroupManager::GetGroup(int32 group_id) {
 	return 0;
 }
 
-deque<GroupMemberInfo*>* PlayerGroupManager::GetGroupMembers(int32 group_id) {
-	if (m_groups.count(group_id) > 0)
-		return m_groups[group_id]->GetMembers();
-
-	return 0;
-}
-
 void PlayerGroupManager::ClearPendingInvite(Entity* member) {
 	MPendingInvites.writelock(__FUNCTION__, __LINE__);
 
@@ -503,7 +496,7 @@ void PlayerGroupManager::SendGroupQuests(int32 group_id, Client* client) {
 	GroupMemberInfo* info = 0;
 	MGroups.readlock(__FUNCTION__, __LINE__);
 	if (m_groups.count(group_id) > 0) {
-		m_groups[group_id]->MGroupMembers.readlock();
+		m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
 		deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
 		deque<GroupMemberInfo*>::iterator itr;
 		for (itr = members->begin(); itr != members->end(); itr++) {
@@ -514,7 +507,7 @@ void PlayerGroupManager::SendGroupQuests(int32 group_id, Client* client) {
 				client->SendQuestJournal(false, info->client);
 			}
 		}
-		m_groups[group_id]->MGroupMembers.releasereadlock();
+		m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 	MGroups.releasereadlock(__FUNCTION__, __LINE__);
 }
@@ -586,7 +579,7 @@ void PlayerGroupManager::UpdateGroupBuffs() {
 		/* loop through the group members and see if any of them have any maintained spells that are group buffs and friendly.
 		if so, update the list of targets and apply/remove effects as needed */
 
-		group->MGroupMembers.readlock();
+		group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
 		for (member_itr = group->GetMembers()->begin(); member_itr != group->GetMembers()->end(); member_itr++) {
 			if ((*member_itr)->client)
 				caster = (*member_itr)->client->GetPlayer();
@@ -729,7 +722,7 @@ void PlayerGroupManager::UpdateGroupBuffs() {
 			}
 			caster->GetMaintainedMutex()->releasereadlock(__FUNCTION__, __LINE__);
 		}
-		group->MGroupMembers.releasereadlock();
+		group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 }
 
@@ -739,7 +732,7 @@ bool PlayerGroupManager::IsInGroup(int32 group_id, Entity* member) {
 	MGroups.readlock(__FUNCTION__, __LINE__);
 
 	if (m_groups.count(group_id) > 0) {
-		m_groups[group_id]->MGroupMembers.readlock();
+		m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
 		deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
 		for (int8 i = 0; i < members->size(); i++) {
 			if (member == members->at(i)->member) {
@@ -747,7 +740,7 @@ bool PlayerGroupManager::IsInGroup(int32 group_id, Entity* member) {
 				break;
 			}
 		}
-		m_groups[group_id]->MGroupMembers.releasereadlock();
+		m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 	}
 
 	MGroups.releasereadlock(__FUNCTION__, __LINE__);

+ 0 - 8
EQ2/source/WorldServer/PlayerGroups.h

@@ -147,14 +147,6 @@ public:
 
 	PlayerGroup* GetGroup(int32 group_id);
 
-	/// <summary>
-	/// Gets the group members for the given group, be sure to call GroupLock() before calling this and ReleaseGroupLock() after you 
-	/// are done with the list.  This is for reading purposes only, the list should never be altered using this function
-	/// </summary>
-	/// <param name='group_id'>ID of the group who's members we want</param>
-	/// <returns>deque pointer of the members in the group</returns>
-	deque<GroupMemberInfo*>* GetGroupMembers(int32 group_id);
-
 	/// <summary>Read locks the group list, no changes to the list should be made when using this</summary>
 	/// <param name='function'>Name of the function called from, used for better debugging in the event of a deadlock</param>
 	/// <param name='line'>Line number that this was called from, used for better debugging in the event of a deadlock</param>

+ 20 - 8
EQ2/source/WorldServer/Spawn.cpp

@@ -120,6 +120,7 @@ Spawn::~Spawn(){
 	vector<Item*>::iterator itr;
 	for (itr = loot_items.begin(); itr != loot_items.end(); itr++)
 		safe_delete(*itr);
+	loot_items.clear();
 
 	RemovePrimaryCommands();
 
@@ -149,11 +150,15 @@ Spawn::~Spawn(){
 	MMovementLoop.unlock();
 
 	m_requiredHistory.writelock(__FUNCTION__, __LINE__);
+	map<int32, LUAHistory*>::iterator lua_itr;
+	for (lua_itr = required_history.begin(); lua_itr != required_history.end(); lua_itr++) {
+		safe_delete(lua_itr->second);
+	}
 	required_history.clear();
 	m_requiredHistory.releasewritelock(__FUNCTION__, __LINE__);
 
-	map<int32, vector<int16>* >::iterator rq_itr;
 	m_requiredQuests.writelock(__FUNCTION__, __LINE__);
+	map<int32, vector<int16>* >::iterator rq_itr;
 	for (rq_itr = required_quests.begin(); rq_itr != required_quests.end(); rq_itr++){
 		safe_delete(rq_itr->second);
 	}
@@ -1924,12 +1929,19 @@ bool Spawn::HasQuestsRequired()
 }
 
 void Spawn::SetRequiredHistory(int32 event_id, int32 value1, int32 value2){
-	LUAHistory set_value;
-	set_value.Value = value1;
-	set_value.Value2 = value2;
-	set_value.SaveNeeded = false;
+	LUAHistory* set_value = new LUAHistory();
+	set_value->Value = value1;
+	set_value->Value2 = value2;
+	set_value->SaveNeeded = false;
 	m_requiredHistory.writelock(__FUNCTION__, __LINE__);
-	required_history[event_id] = set_value;
+	if (required_history.count(event_id) == 0)
+		required_history.insert(make_pair(event_id, set_value));
+	else
+	{
+		LUAHistory* tmp_value = required_history[event_id];
+		required_history[event_id] = set_value;
+		safe_delete(tmp_value);
+	}
 	m_requiredHistory.releasewritelock(__FUNCTION__, __LINE__);
 }
 
@@ -3210,12 +3222,12 @@ bool Spawn::MeetsSpawnAccessRequirements(Player* player){
 	//Now check if the player meets all history requirements
 	m_requiredHistory.readlock(__FUNCTION__, __LINE__);
 	if (required_history.size() > 0){
-		map<int32, LUAHistory>::iterator itr;
+		map<int32, LUAHistory*>::iterator itr;
 		for (itr = required_history.begin(); itr != required_history.end(); itr++){
 			player->AddHistoryRequiredSpawn(this, itr->first);
 			LUAHistory* player_history = player->GetLUAHistory(itr->first);
 			if (player_history){
-				if (player_history->Value != itr->second.Value || player_history->Value2 != itr->second.Value2)
+				if (player_history->Value != itr->second->Value || player_history->Value2 != itr->second->Value2)
 					ret = false;
 			}
 			else

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

@@ -1162,7 +1162,7 @@ protected:
 	int32			pickup_item_id;
 	int32			pickup_unique_item_id;
 	map<int32, vector<int16>* > required_quests;
-	map<int32, LUAHistory> required_history;
+	map<int32, LUAHistory*> required_history;
 	EquipmentItemList equipment_list;
 
 	MutexList<SpawnProximity*> spawn_proximities;

+ 99 - 57
EQ2/source/WorldServer/SpellProcess.cpp

@@ -256,10 +256,16 @@ void SpellProcess::Process(){
 
 				world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 				deque<GroupMemberInfo*>::iterator itr2;
-				deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(itr->first);
-				for (itr2 = members->begin(); itr2 != members->end(); itr2++) {
-					if ((*itr2)->client)
-						ClientPacketFunctions::SendHeroicOPUpdate((*itr2)->client, itr->second);
+				PlayerGroup* group = world.GetGroupManager()->GetGroup(itr->first);
+				if (group)
+				{
+					group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+					deque<GroupMemberInfo*>* members = group->GetMembers();
+					for (itr2 = members->begin(); itr2 != members->end(); itr2++) {
+						if ((*itr2)->client)
+							ClientPacketFunctions::SendHeroicOPUpdate((*itr2)->client, itr->second);
+					}
+					group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 				}
 				world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
 
@@ -1508,10 +1514,16 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive){
 
 					world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 					deque<GroupMemberInfo*>::iterator itr;
-					deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(group_id);
-					for (itr = members->begin(); itr != members->end(); itr++) {
-						if ((*itr)->client)
-							ClientPacketFunctions::SendHeroicOPUpdate((*itr)->client, ho);
+					PlayerGroup* group = world.GetGroupManager()->GetGroup(group_id);
+					if (group)
+					{
+						group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+						deque<GroupMemberInfo*>* members = group->GetMembers();
+						for (itr = members->begin(); itr != members->end(); itr++) {
+							if ((*itr)->client)
+								ClientPacketFunctions::SendHeroicOPUpdate((*itr)->client, ho);
+						}
+						group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 					}
 					world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
 
@@ -1822,26 +1834,32 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 						world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 						// get group members
-						deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Entity*)caster)->GetGroupMemberInfo()->group_id);
-						deque<GroupMemberInfo*>::iterator itr;
-
-						// iterate through list of group members
-						for (itr = members->begin(); itr != members->end(); itr++) 
+						PlayerGroup* group = world.GetGroupManager()->GetGroup(((Entity*)caster)->GetGroupMemberInfo()->group_id);
+						if (group)
 						{
-							// get group member player info
-							Entity* group_member = (*itr)->member;
+							group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+							deque<GroupMemberInfo*>* members = group->GetMembers();
+							deque<GroupMemberInfo*>::iterator itr;
 
-							// if the group member is in the casters zone, and is alive
-							if (group_member->GetZone() == luaspell->caster->GetZone() && group_member->Alive()){
-								luaspell->targets.push_back(group_member->GetID());
-								if (group_member->HasPet()){
-									Entity* pet = group_member->GetPet();
-									if (!pet)
-										pet = group_member->GetCharmedPet();
-									if (pet)
-										luaspell->targets.push_back(pet->GetID());
+							// iterate through list of group members
+							for (itr = members->begin(); itr != members->end(); itr++)
+							{
+								// get group member player info
+								Entity* group_member = (*itr)->member;
+
+								// if the group member is in the casters zone, and is alive
+								if (group_member->GetZone() == luaspell->caster->GetZone() && group_member->Alive()) {
+									luaspell->targets.push_back(group_member->GetID());
+									if (group_member->HasPet()) {
+										Entity* pet = group_member->GetPet();
+										if (!pet)
+											pet = group_member->GetCharmedPet();
+										if (pet)
+											luaspell->targets.push_back(pet->GetID());
+									}
 								}
 							}
+							group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 						}
 
 						world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -1981,17 +1999,23 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 						world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 						deque<GroupMemberInfo*>::iterator itr;
-						deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Player*)target)->GetGroupMemberInfo()->group_id);
-
-						// iterate through players group members
-						for (itr = members->begin(); itr != members->end(); itr++) 
+						PlayerGroup* group = world.GetGroupManager()->GetGroup(((Player*)target)->GetGroupMemberInfo()->group_id);
+						if (group)
 						{
-							Entity* group_member = (*itr)->member;
+							group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+							deque<GroupMemberInfo*>* members = group->GetMembers();
+
+							// iterate through players group members
+							for (itr = members->begin(); itr != members->end(); itr++)
+							{
+								Entity* group_member = (*itr)->member;
 
-							// if the group member is in the same zone as caster, and group member is alive, and group member is within distance
-							if (group_member->GetZone() == caster->GetZone() && group_member->Alive() && caster->GetDistance(group_member) <= data->range
-								&& (group_member == target || !group_member->IsAOEImmune()))
-								luaspell->targets.push_back(group_member->GetID()); // add as target
+								// if the group member is in the same zone as caster, and group member is alive, and group member is within distance
+								if (group_member->GetZone() == caster->GetZone() && group_member->Alive() && caster->GetDistance(group_member) <= data->range
+									&& (group_member == target || !group_member->IsAOEImmune()))
+									luaspell->targets.push_back(group_member->GetID()); // add as target
+							}
+							group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 						}
 
 						world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -2023,14 +2047,20 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 						world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 						deque<GroupMemberInfo*>::iterator itr;
-						deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Player*)target)->GetGroupMemberInfo()->group_id);
-						Entity* group_member = 0;
-						for(itr = members->begin(); itr != members->end(); itr++) {
-							group_member = (*itr)->member;
-							//Check if group member is in the same zone in range of the spell and dead
-							if(group_member->GetZone() == target->GetZone() && !group_member->Alive() && target->GetDistance(group_member) <= data->radius){
-								luaspell->targets.push_back(group_member->GetID());
+						PlayerGroup* group = world.GetGroupManager()->GetGroup(((Player*)target)->GetGroupMemberInfo()->group_id);
+						if (group)
+						{
+							group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+							deque<GroupMemberInfo*>* members = group->GetMembers();
+							Entity* group_member = 0;
+							for (itr = members->begin(); itr != members->end(); itr++) {
+								group_member = (*itr)->member;
+								//Check if group member is in the same zone in range of the spell and dead
+								if (group_member->GetZone() == target->GetZone() && !group_member->Alive() && target->GetDistance(group_member) <= data->radius) {
+									luaspell->targets.push_back(group_member->GetID());
+								}
 							}
+							group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 						}
 
 						world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -2053,20 +2083,26 @@ void SpellProcess::GetPlayerGroupTargets(Player* target, Spawn* caster, LuaSpell
 	{
 		if (((Player*)target)->GetGroupMemberInfo())
 		{
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(((Player*)target)->GetGroupMemberInfo()->group_id);
-			deque<GroupMemberInfo*>::iterator itr;
-			GroupMemberInfo* info = 0;
-
-			for (itr = members->begin(); itr != members->end(); itr++) {
-				info = *itr;
-				if (info == ((Player*)target)->GetGroupMemberInfo())
-					continue;
-				else if (info && info->client &&
-					info->client->GetPlayer()->GetZone() == ((Player*)target)->GetZone() && info->client->GetPlayer()->Alive()
-					&& (bypassRangeChecks || caster->GetDistance((Entity*)info->client->GetPlayer()) <= luaspell->spell->GetSpellData()->range))
-				{
-					luaspell->targets.push_back(info->client->GetPlayer()->GetID());
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(((Player*)target)->GetGroupMemberInfo()->group_id);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				deque<GroupMemberInfo*>::iterator itr;
+				GroupMemberInfo* info = 0;
+
+				for (itr = members->begin(); itr != members->end(); itr++) {
+					info = *itr;
+					if (info == ((Player*)target)->GetGroupMemberInfo())
+						continue;
+					else if (info && info->client &&
+						info->client->GetPlayer()->GetZone() == ((Player*)target)->GetZone() && info->client->GetPlayer()->Alive()
+						&& (bypassRangeChecks || caster->GetDistance((Entity*)info->client->GetPlayer()) <= luaspell->spell->GetSpellData()->range))
+					{
+						luaspell->targets.push_back(info->client->GetPlayer()->GetID());
+					}
 				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 		}
 	}
@@ -2365,10 +2401,16 @@ void SpellProcess::KillHOBySpawnID(int32 spawn_id) {
 
 			world.GetGroupManager()->GroupLock(__FUNCTION__ , __LINE__);
 			deque<GroupMemberInfo*>::iterator itr3;
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(itr2->first);
-			for (itr3 = members->begin(); itr3 != members->end(); itr3++) {
-				if ((*itr3)->client)
-					ClientPacketFunctions::SendHeroicOPUpdate((*itr3)->client, itr2->second);
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(itr2->first);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				for (itr3 = members->begin(); itr3 != members->end(); itr3++) {
+					if ((*itr3)->client)
+						ClientPacketFunctions::SendHeroicOPUpdate((*itr3)->client, itr2->second);
+				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 			world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
 

+ 11 - 5
EQ2/source/WorldServer/World.cpp

@@ -1702,11 +1702,17 @@ void World::CreateGuild(const char* guild_name, Client* leader, int32 group_id)
 	if (leader && group_id > 0) {
 		GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
-		deque<GroupMemberInfo*>* members = GetGroupManager()->GetGroupMembers(group_id);
-		for (itr = members->begin(); itr != members->end(); itr++) {
-			gmi = *itr;
-			if (gmi->client && gmi->client != leader && !gmi->client->GetPlayer()->GetGuild())
-				guild->InvitePlayer(gmi->client, leader->GetPlayer()->GetName());
+		PlayerGroup* group = world.GetGroupManager()->GetGroup(group_id);
+		if (group)
+		{
+			group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+			deque<GroupMemberInfo*>* members = group->GetMembers();
+			for (itr = members->begin(); itr != members->end(); itr++) {
+				gmi = *itr;
+				if (gmi->client && gmi->client != leader && !gmi->client->GetPlayer()->GetGuild())
+					guild->InvitePlayer(gmi->client, leader->GetPlayer()->GetName());
+			}
+			group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 		}
 
 		GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);

+ 15 - 9
EQ2/source/WorldServer/client.cpp

@@ -4505,17 +4505,23 @@ void Client::CastGroupOrSelf(Entity* source, uint32 spellID, uint32 spellTier, f
 		GroupMemberInfo* gmi = GetPlayer()->GetGroupMemberInfo();
 		if (gmi && gmi->group_id)
 		{
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(gmi->group_id);
-			for (int8 i = 0; i < members->size(); i++) {
-				Entity* member = members->at(i)->member;
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				for (int8 i = 0; i < members->size(); i++) {
+					Entity* member = members->at(i)->member;
 
-				if (!member->Alive() || (member->GetZone() != source->GetZone()))
-					continue;
-				// if we have a radius provided then check if the group member is outside the radius or not
-				if (restrictiveRadius > 0.0f && member->GetDistance(source) > restrictiveRadius)
-					continue;
+					if (!member->Alive() || (member->GetZone() != source->GetZone()))
+						continue;
+					// if we have a radius provided then check if the group member is outside the radius or not
+					if (restrictiveRadius > 0.0f && member->GetDistance(source) > restrictiveRadius)
+						continue;
 
-				spellProcess->CastInstant(spell, source, (Entity*)GetPlayer());
+					spellProcess->CastInstant(spell, source, (Entity*)GetPlayer());
+				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 		}
 		else

+ 39 - 25
EQ2/source/WorldServer/zoneserver.cpp

@@ -4127,24 +4127,30 @@ void ZoneServer::SendCalculatedXP(Player* player, Spawn* victim){
 		if (player->GetGroupMemberInfo()) {
 			world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(player->GetGroupMemberInfo()->group_id);
-			deque<GroupMemberInfo*>::iterator itr;
-			for (itr = members->begin(); itr != members->end(); itr++) {
-				GroupMemberInfo* gmi = *itr;
-				if (gmi->client) {
-					Player* group_member = gmi->client->GetPlayer();
-					float xp = group_member->CalculateXP(victim) / members->size();
-					if (xp > 0) {
-						int16 level = group_member->GetLevel();
-						if (group_member->AddXP((int32)xp)) {
-							gmi->client->Message(CHANNEL_COLOR_EXP, "You gain %u experience!", (int32)xp);
-							LogWrite(PLAYER__DEBUG, 0, "Player", "Player: %s earned %u experience (GroupID %u)", group_member->GetName(), (int32)xp, player->GetGroupMemberInfo()->group_id);
-							if(group_member->GetLevel() != level)
-								gmi->client->ChangeLevel(level, group_member->GetLevel());
-							group_member->SetCharSheetChanged(true);
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(player->GetGroupMemberInfo()->group_id);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				deque<GroupMemberInfo*>::iterator itr;
+				for (itr = members->begin(); itr != members->end(); itr++) {
+					GroupMemberInfo* gmi = *itr;
+					if (gmi->client) {
+						Player* group_member = gmi->client->GetPlayer();
+						float xp = group_member->CalculateXP(victim) / members->size();
+						if (xp > 0) {
+							int16 level = group_member->GetLevel();
+							if (group_member->AddXP((int32)xp)) {
+								gmi->client->Message(CHANNEL_COLOR_EXP, "You gain %u experience!", (int32)xp);
+								LogWrite(PLAYER__DEBUG, 0, "Player", "Player: %s earned %u experience (GroupID %u)", group_member->GetName(), (int32)xp, player->GetGroupMemberInfo()->group_id);
+								if (group_member->GetLevel() != level)
+									gmi->client->ChangeLevel(level, group_member->GetLevel());
+								group_member->SetCharSheetChanged(true);
+							}
 						}
 					}
 				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 
 			world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
@@ -6030,18 +6036,26 @@ void ZoneServer::SendEpicMobDeathToGuild(Player* killer, Spawn* victim) {
 			world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
 
 			deque<GroupMemberInfo*>::iterator itr;
-			deque<GroupMemberInfo*>* members = world.GetGroupManager()->GetGroupMembers(killer->GetGroupMemberInfo()->group_id);
-			for (itr = members->begin(); itr != members->end(); itr++) {
-				GroupMemberInfo* gmi = *itr;
-				if (gmi->client) {
-					Player* group_member = gmi->client->GetPlayer();
-					if (group_member->GetGuild()) {
-						Guild* guild = group_member->GetGuild();
-						string message = Guild::GetEpicMobDeathMessage(group_member->GetName(), victim->GetName());
-						guild->AddNewGuildEvent(GUILD_EVENT_KILLS_EPIC_MONSTER, message.c_str(), Timer::GetUnixTimeStamp());
-						guild->SendMessageToGuild(GUILD_EVENT_KILLS_EPIC_MONSTER, message.c_str());
+
+
+			PlayerGroup* group = world.GetGroupManager()->GetGroup(killer->GetGroupMemberInfo()->group_id);
+			if (group)
+			{
+				group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
+				deque<GroupMemberInfo*>* members = group->GetMembers();
+				for (itr = members->begin(); itr != members->end(); itr++) {
+					GroupMemberInfo* gmi = *itr;
+					if (gmi->client) {
+						Player* group_member = gmi->client->GetPlayer();
+						if (group_member->GetGuild()) {
+							Guild* guild = group_member->GetGuild();
+							string message = Guild::GetEpicMobDeathMessage(group_member->GetName(), victim->GetName());
+							guild->AddNewGuildEvent(GUILD_EVENT_KILLS_EPIC_MONSTER, message.c_str(), Timer::GetUnixTimeStamp());
+							guild->SendMessageToGuild(GUILD_EVENT_KILLS_EPIC_MONSTER, message.c_str());
+						}
 					}
 				}
+				group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
 			}
 
 			world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);