Browse Source

Protection on group member info when updates are made

Prevents corruption in the group member pointers.. clients couldn't see each other in group lists or chat to each other depending on special conditions
image 3 years ago
parent
commit
5bf65b9399

+ 12 - 15
EQ2/source/WorldServer/Entity.cpp

@@ -2347,23 +2347,20 @@ void Entity::RemoveSafefallSpell(LuaSpell* spell){
 		((Player*)this)->SetPlayerControlFlag(4, 32, false);
 }
 
-void Entity::UpdateGroupMemberInfo() {
-	if (!group_member_info)
+void Entity::UpdateGroupMemberInfo(bool inGroupMgrLock, bool groupMembersLocked) {
+	if (!group_member_info || group_id == 0)
 		return;
 
-	group_member_info->class_id = GetAdventureClass();
-	group_member_info->hp_max = GetTotalHP();
-	group_member_info->hp_current = GetHP();
-	group_member_info->level_max = GetLevel();
-	group_member_info->level_current = GetLevel();
-	group_member_info->name = string(GetName());
-	group_member_info->power_current = GetPower();
-	group_member_info->power_max = GetTotalPower();
-	group_member_info->race_id = GetRace();
-	if (GetZone())
-		group_member_info->zone = GetZone()->GetZoneDescription();
-	else
-		group_member_info->zone = "Unknown";
+	if(!inGroupMgrLock)
+		world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
+
+	PlayerGroup* group = world.GetGroupManager()->GetGroup(group_id);
+
+	if (group)
+		group->UpdateGroupMemberInfo(this, groupMembersLocked);
+
+	if(!inGroupMgrLock)
+		world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
 }
 
 #include "WorldDatabase.h"

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

@@ -793,7 +793,7 @@ public:
 
 	GroupMemberInfo* GetGroupMemberInfo() { return group_member_info; }
 	void SetGroupMemberInfo(GroupMemberInfo* info) { group_member_info = info; }
-	void UpdateGroupMemberInfo();
+	void UpdateGroupMemberInfo(bool inGroupMgrLock=false, bool groupMembersLocked=false);
 
 	void CustomizeAppearance(PacketStruct* packet);
 

+ 34 - 5
EQ2/source/WorldServer/PlayerGroups.cpp

@@ -62,10 +62,10 @@ bool PlayerGroup::AddMember(Entity* member) {
 		gmi->client = 0;
 
 	member->SetGroupMemberInfo(gmi);
-	member->UpdateGroupMemberInfo();
-
+	member->group_id = gmi->group_id;
 	MGroupMembers.writelock();
 	m_members.push_back(gmi);
+	member->UpdateGroupMemberInfo(true, true);
 	MGroupMembers.releasewritelock();
 
 	SendGroupUpdate();
@@ -257,14 +257,15 @@ void PlayerGroupManager::NewGroup(Entity* leader) {
 
 	// Create a new group with the valid ID we got from above
 	PlayerGroup* new_group = new PlayerGroup(m_nextGroupID);
+
+	// Add the new group to the list (need to do this first, AddMember needs ref to the PlayerGroup ptr -> UpdateGroupMemberInfo)
+	m_groups[m_nextGroupID] = new_group;
+
 	// Add the leader to the group
 	new_group->AddMember(leader);
 
 	leader->GetGroupMemberInfo()->leader = true;
 
-	// Add the new group to the list
-	m_groups[m_nextGroupID] = new_group;
-
 	MGroups.releasewritelock(__FUNCTION__, __LINE__);
 }
 
@@ -767,4 +768,32 @@ void PlayerGroup::RemoveClientReference(Client* remove) {
 		}
 	}
 	MGroupMembers.releasewritelock();
+}
+
+void PlayerGroup::UpdateGroupMemberInfo(Entity* ent, bool groupMembersLocked) {
+	Player* player = (Player*)ent;
+
+	if (!player || !player->GetGroupMemberInfo())
+		return;
+
+	if(!groupMembersLocked)
+		MGroupMembers.writelock();
+
+	GroupMemberInfo* group_member_info = player->GetGroupMemberInfo();
+	player->GetGroupMemberInfo()->class_id = player->GetAdventureClass();
+	group_member_info->hp_max = player->GetTotalHP();
+	group_member_info->hp_current = player->GetHP();
+	group_member_info->level_max = player->GetLevel();
+	group_member_info->level_current = player->GetLevel();
+	group_member_info->name = string(player->GetName());
+	group_member_info->power_current = player->GetPower();
+	group_member_info->power_max = player->GetTotalPower();
+	group_member_info->race_id = player->GetRace();
+	if (player->GetZone())
+		group_member_info->zone = player->GetZone()->GetZoneDescription();
+	else
+		group_member_info->zone = "Unknown";
+
+	if(!groupMembersLocked)
+		MGroupMembers.releasewritelock();
 }

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

@@ -84,6 +84,7 @@ public:
 	void MakeLeader(Entity* new_leader);
 
 	void RemoveClientReference(Client* remove);
+	void UpdateGroupMemberInfo(Entity* ent, bool groupMembersLocked=false);
 
 	Mutex MGroupMembers;				// Mutex for the group members
 private:

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

@@ -1499,7 +1499,7 @@ void World::RejoinGroup(Client* client, int32 group_id){
 			info->member = client->GetPlayer();
 			client->GetPlayer()->SetGroup(group);
 			client->GetPlayer()->SetGroupMemberInfo(info);
-			client->GetPlayer()->UpdateGroupMemberInfo();
+			client->GetPlayer()->UpdateGroupMemberInfo(true, true);
 			LogWrite(PLAYER__DEBUG, 0, "Player", "Identified group match for player %s to group id %u", name.c_str(), group_id);
 			match = true;
 			break;

+ 4 - 4
EQ2/source/WorldServer/client.cpp

@@ -1338,6 +1338,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 		if (!IsReadyForSpawns())
 			SetReadyForSpawns(true);
 		SendCharInfo();
+		world.RejoinGroup(this, rejoin_group_id);
 		pos_update.Start();
 		quest_pos_timer.Start();
 		break;
@@ -3513,9 +3514,6 @@ void Client::Zone(ZoneServer* new_zone, bool set_coords) {
 		return;
 	}
 
-	// block out the member info for the group
-	TempRemoveGroup();
-
 	client_zoning = true;
 	LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Setting player Resurrecting to 'true'", __FUNCTION__);
 	player->SetResurrecting(true);
@@ -3543,6 +3541,9 @@ void Client::Zone(ZoneServer* new_zone, bool set_coords) {
 		world.GetGroupManager()->SendGroupUpdate(player->GetGroupMemberInfo()->group_id, this);
 	}
 
+	// block out the member info for the group
+	TempRemoveGroup();
+
 	UpdateTimeStampFlag(ZONE_UPDATE_FLAG);
 
 	if (set_coords)
@@ -8703,7 +8704,6 @@ bool Client::HandleNewLogin(int32 account_id, int32 access_code)
 				new_client_login = true;
 				GetCurrentZone()->AddClient(this); //add to zones client list
 
-				world.RejoinGroup(this, rejoin_group_id);
 				zone_list.AddClientToMap(player->GetName(), this);
 			}
 			else {