[Crash] Fix dangling Group member pointers for Bots. (#3134)

* [Crash] Fix dangling Group member pointers for Bots.

* fixes for edge cases
This commit is contained in:
Aeadoin 2023-03-21 11:57:04 -04:00 committed by GitHub
parent 4fe44f4cb6
commit fe2dcb6544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 58 deletions

View File

@ -425,11 +425,6 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
cur_end = max_end; cur_end = max_end;
// Safety Check to confirm we have a valid group
if (HasGroup() && !GetGroup()->IsGroupMember(GetBotOwner())) {
Bot::RemoveBotFromGroup(this, GetGroup());
}
// Safety Check to confirm we have a valid raid // Safety Check to confirm we have a valid raid
if (HasRaid() && !GetRaid()->IsRaidMember(GetBotOwner()->CastToClient())) { if (HasRaid() && !GetRaid()->IsRaidMember(GetBotOwner()->CastToClient())) {
Bot::RemoveBotFromRaid(this); Bot::RemoveBotFromRaid(this);
@ -3111,7 +3106,6 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint
raid->GetGroupLeader(r_group)->CastToClient() : bot_owner; raid->GetGroupLeader(r_group)->CastToClient() : bot_owner;
} else if (bot_group) { } else if (bot_group) {
bot_group->VerifyGroup();
leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner);
} else { } else {
@ -3321,11 +3315,18 @@ bool Bot::Spawn(Client* botCharacterOwner) {
} }
} }
if (Raid* raid = entity_list.GetRaidByBotName(GetName())) Raid* raid = nullptr;
{ Group* group = nullptr;
if (raid = entity_list.GetRaidByBotName(GetName())) {
raid->VerifyRaid(); raid->VerifyRaid();
SetRaidGrouped(true); SetRaidGrouped(true);
} }
else if (group = entity_list.GetGroupByMobName(GetName())) {
group->VerifyGroup();
SetGrouped(true);
}
return true; return true;
} }
@ -3863,9 +3864,7 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
bool Bot::AddBotToGroup(Bot* bot, Group* group) { bool Bot::AddBotToGroup(Bot* bot, Group* group) {
bool Result = false; bool Result = false;
if (bot && group) { if (bot && group && group->AddMember(bot)) {
// Add bot to this group
if (group->AddMember(bot)) {
if (group->GetLeader()) { if (group->GetLeader()) {
bot->SetFollowID(group->GetLeader()->GetID()); bot->SetFollowID(group->GetLeader()->GetID());
// Need to send this only once when a group is formed with a bot so the client knows it is also the group leader // Need to send this only once when a group is formed with a bot so the client knows it is also the group leader
@ -3878,7 +3877,6 @@ bool Bot::AddBotToGroup(Bot* bot, Group* group) {
group->VerifyGroup(); group->VerifyGroup();
Result = true; Result = true;
} }
}
return Result; return Result;
} }
@ -6680,8 +6678,12 @@ void Bot::Camp(bool save_to_database) {
Save(); Save();
} }
if (HasGroup() || HasRaid()) {
Zone();
} else {
Depop(); Depop();
} }
}
void Bot::Zone() { void Bot::Zone() {
Raid* raid = entity_list.GetRaidByBotName(GetName()); Raid* raid = entity_list.GetRaidByBotName(GetName());
@ -8582,6 +8584,7 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3
return; return;
} }
if (!leader->spawned) {
if (!leader->Spawn(c)) { if (!leader->Spawn(c)) {
c->Message( c->Message(
Chat::White, Chat::White,
@ -8594,12 +8597,21 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3
safe_delete(leader); safe_delete(leader);
return; return;
} }
}
auto* g = new Group(leader); auto group = leader->GetGroupByLeaderName();
auto raid = leader->GetRaid();
if (!raid && group) {
group->SetLeader(leader);
}
else if (!raid) {
group = new Group(leader);
entity_list.AddGroup(group);
database.SetGroupID(leader->GetCleanName(), group->GetID(), leader->GetBotID());
database.SetGroupLeaderName(group->GetID(), leader->GetCleanName());
}
entity_list.AddGroup(g);
database.SetGroupID(leader->GetCleanName(), g->GetID(), leader->GetBotID());
database.SetGroupLeaderName(g->GetID(), leader->GetCleanName());
leader->SetFollowID(c->GetID()); leader->SetFollowID(c->GetID());
uint32 botgroup_id = 0; uint32 botgroup_id = 0;
@ -8686,6 +8698,7 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3
continue; continue;
} }
if (!member->spawned) {
if (!member->Spawn(c)) { if (!member->Spawn(c)) {
c->Message( c->Message(
Chat::White, Chat::White,
@ -8702,7 +8715,16 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3
spawned_bot_count++; spawned_bot_count++;
bot_class_spawned_count[member->GetClass() - 1]++; bot_class_spawned_count[member->GetClass() - 1]++;
Bot::AddBotToGroup(member, g); if (group) {
Bot::AddBotToGroup(member, group);
}
}
}
if (group) {
group->VerifyGroup();
} else if (raid) {
raid->VerifyRaid();
} }
c->Message( c->Message(

View File

@ -141,6 +141,7 @@ public:
bool HasGroup() final { return GetGroup() != nullptr; } bool HasGroup() final { return GetGroup() != nullptr; }
Raid* GetRaid() final { return entity_list.GetRaidByBot(this); } Raid* GetRaid() final { return entity_list.GetRaidByBot(this); }
Group* GetGroup() final { return entity_list.GetGroupByMob(this); } Group* GetGroup() final { return entity_list.GetGroupByMob(this); }
Group* GetGroupByLeaderName() { return entity_list.GetGroupByLeaderName(GetName()); }
// Common, but informal "interfaces" with Client object // Common, but informal "interfaces" with Client object
uint32 CharacterID() const { return GetBotID(); } uint32 CharacterID() const { return GetBotID(); }

View File

@ -2119,6 +2119,18 @@ Group *EntityList::GetGroupByMob(Mob *mob)
return nullptr; return nullptr;
} }
Group *EntityList::GetGroupByMobName(const char* name)
{
for (const auto& g : group_list) {
for (const auto& m : g->membername) {
if (strcmp(m, name) == 0) {
return g;
}
}
}
return nullptr;
}
Group *EntityList::GetGroupByLeaderName(const char *leader) Group *EntityList::GetGroupByLeaderName(const char *leader)
{ {
std::list<Group *>::iterator iterator; std::list<Group *>::iterator iterator;

View File

@ -193,6 +193,7 @@ public:
NPC* GetRandomNPC(const glm::vec3& location = glm::vec3(0.f), float distance = 0, NPC* exclude_npc = nullptr); NPC* GetRandomNPC(const glm::vec3& location = glm::vec3(0.f), float distance = 0, NPC* exclude_npc = nullptr);
Mob* GetRandomMob(const glm::vec3& location = glm::vec3(0.f), float distance = 0, Mob* exclude_mob = nullptr); Mob* GetRandomMob(const glm::vec3& location = glm::vec3(0.f), float distance = 0, Mob* exclude_mob = nullptr);
Group* GetGroupByMob(Mob* mob); Group* GetGroupByMob(Mob* mob);
Group* GetGroupByMobName(const char* name);
Group* GetGroupByBot(Bot* bot); Group* GetGroupByBot(Bot* bot);
bool IsInSameGroupOrRaidGroup(Client *client1, Client *client2); bool IsInSameGroupOrRaidGroup(Client *client1, Client *client2);
Group *GetGroupByClient(Client* client); Group *GetGroupByClient(Client* client);

View File

@ -547,11 +547,13 @@ bool Group::UpdatePlayer(Mob* update) {
void Group::MemberZoned(Mob* removemob) { void Group::MemberZoned(Mob* removemob) {
uint32 i; uint32 i;
if (removemob == nullptr) if (!removemob) {
return; return;
}
if(removemob == GetLeader()) if (removemob == GetLeader()) {
SetLeader(nullptr); SetLeader(nullptr);
}
//should NOT clear the name, it is used for world communication. //should NOT clear the name, it is used for world communication.
for (auto & m : members) { for (auto & m : members) {
@ -560,17 +562,21 @@ void Group::MemberZoned(Mob* removemob) {
} }
} }
if(removemob->IsClient() && HasRole(removemob, RoleAssist)) if (removemob->IsClient() && HasRole(removemob, RoleAssist)) {
SetGroupAssistTarget(0); SetGroupAssistTarget(0);
}
if(removemob->IsClient() && HasRole(removemob, RoleTank)) if (removemob->IsClient() && HasRole(removemob, RoleTank)) {
SetGroupTankTarget(0); SetGroupTankTarget(0);
}
if(removemob->IsClient() && HasRole(removemob, RolePuller)) if (removemob->IsClient() && HasRole(removemob, RolePuller)) {
SetGroupPullerTarget(0); SetGroupPullerTarget(0);
}
if (removemob->IsClient() && removemob == mentoree) if (removemob->IsClient() && removemob == mentoree) {
mentoree = nullptr; mentoree = nullptr;
}
if (RuleB(Bots, Enabled)) { if (RuleB(Bots, Enabled)) {
Bot::UpdateGroupCastingRoles(this); Bot::UpdateGroupCastingRoles(this);