[11534] Guild disban memory losses and unsafe code.

* Make sure that guild object deleted in all cases after disband.
* Avoid recusive like way call Disband from DelMember
This commit is contained in:
VladimirMangos 2011-05-25 03:19:42 +04:00
parent b5c3ec952f
commit 2cbde12458
6 changed files with 59 additions and 19 deletions

View file

@ -301,10 +301,8 @@ bool Guild::CheckGuildStructure()
int32 GM_rights = GetRank(m_LeaderGuid); int32 GM_rights = GetRank(m_LeaderGuid);
if (GM_rights == -1) if (GM_rights == -1)
{ {
DelMember(m_LeaderGuid); if (DelMember(m_LeaderGuid))
// check no members case (disbanded) return false; // guild will disbanded and deleted in caller
if (members.empty())
return false;
} }
else if (GM_rights != GR_GUILDMASTER) else if (GM_rights != GR_GUILDMASTER)
SetLeader(m_LeaderGuid); SetLeader(m_LeaderGuid);
@ -488,7 +486,15 @@ void Guild::SetLeader(ObjectGuid guid)
CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", guid.GetCounter(), m_Id); CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", guid.GetCounter(), m_Id);
} }
void Guild::DelMember(ObjectGuid guid, bool isDisbanding) /**
* Remove character from guild
*
* @param guid Character that removed from guild
* @param isDisbanding Flag set if function called from Guild::Disband, so not need update DB in per-member mode only or leader update
*
* @return true, if guild need to be disband and erase (no members or can't setup leader)
*/
bool Guild::DelMember(ObjectGuid guid, bool isDisbanding)
{ {
uint32 lowguid = guid.GetCounter(); uint32 lowguid = guid.GetCounter();
@ -513,11 +519,9 @@ void Guild::DelMember(ObjectGuid guid, bool isDisbanding)
newLeaderGUID = ObjectGuid(HIGHGUID_PLAYER, i->first); newLeaderGUID = ObjectGuid(HIGHGUID_PLAYER, i->first);
} }
} }
if (!best) if (!best)
{ return true;
Disband();
return;
}
SetLeader(newLeaderGUID); SetLeader(newLeaderGUID);
@ -547,6 +551,8 @@ void Guild::DelMember(ObjectGuid guid, bool isDisbanding)
if (!isDisbanding) if (!isDisbanding)
UpdateAccountsNumber(); UpdateAccountsNumber();
return members.empty();
} }
void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language) void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language)
@ -685,6 +691,11 @@ void Guild::SetRankRights(uint32 rankId, uint32 rights)
CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id); CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id);
} }
/**
* Disband guild including cleanup structures and DB
*
* Note: guild object need deleted after this in caller code.
*/
void Guild::Disband() void Guild::Disband()
{ {
BroadcastEvent(GE_DISBANDED); BroadcastEvent(GE_DISBANDED);

View file

@ -324,7 +324,7 @@ class Guild
void SetLeader(ObjectGuid guid); void SetLeader(ObjectGuid guid);
bool AddMember(ObjectGuid plGuid, uint32 plRank); bool AddMember(ObjectGuid plGuid, uint32 plRank);
void DelMember(ObjectGuid guid, bool isDisbanding = false); bool DelMember(ObjectGuid guid, bool isDisbanding = false);
//lowest rank is the count of ranks - 1 (the highest rank_id in table) //lowest rank is the count of ranks - 1 (the highest rank_id in table)
uint32 GetLowestRank() const { return m_Ranks.size() - 1; } uint32 GetLowestRank() const { return m_Ranks.size() - 1; }

View file

@ -177,7 +177,14 @@ void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket)
return; return;
} }
guild->DelMember(slot->guid); // possible last member removed, do cleanup, and no need events
if (guild->DelMember(slot->guid))
{
guild->Disband();
delete guild;
return;
}
// Put record into guild log // Put record into guild log
guild->LogGuildEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, GetPlayer()->GetObjectGuid(), slot->guid); guild->LogGuildEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, GetPlayer()->GetObjectGuid(), slot->guid);
@ -376,16 +383,23 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/)
if (_player->GetObjectGuid() == guild->GetLeaderGuid()) if (_player->GetObjectGuid() == guild->GetLeaderGuid())
{ {
guild->Disband(); guild->Disband();
delete guild;
return;
}
SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), ERR_PLAYER_NO_MORE_IN_GUILD);
if (guild->DelMember(_player->GetObjectGuid()))
{
guild->Disband();
delete guild;
return; return;
} }
guild->DelMember(_player->GetObjectGuid());
// Put record into guild log // Put record into guild log
guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetObjectGuid()); guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetObjectGuid());
guild->BroadcastEvent(GE_LEFT, _player->GetObjectGuid(), _player->GetName()); guild->BroadcastEvent(GE_LEFT, _player->GetObjectGuid(), _player->GetName());
SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), ERR_PLAYER_NO_MORE_IN_GUILD);
} }
void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/)
@ -406,6 +420,7 @@ void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/)
} }
guild->Disband(); guild->Disband();
delete guild;
DEBUG_LOG("WORLD: Guild Successfully Disbanded"); DEBUG_LOG("WORLD: Guild Successfully Disbanded");
} }

View file

@ -3608,7 +3608,12 @@ bool ChatHandler::HandleGuildUninviteCommand(char *args)
if (!targetGuild) if (!targetGuild)
return false; return false;
targetGuild->DelMember(target_guid); if (targetGuild->DelMember(target_guid))
{
targetGuild->Disband();
delete targetGuild;
}
return true; return true;
} }
@ -3651,7 +3656,7 @@ bool ChatHandler::HandleGuildDeleteCommand(char* args)
return false; return false;
char* guildStr = ExtractQuotedArg(&args); char* guildStr = ExtractQuotedArg(&args);
if(!guildStr) if (!guildStr)
return false; return false;
std::string gld = guildStr; std::string gld = guildStr;
@ -3660,7 +3665,8 @@ bool ChatHandler::HandleGuildDeleteCommand(char* args)
if (!targetGuild) if (!targetGuild)
return false; return false;
targetGuild->Disband (); targetGuild->Disband();
delete targetGuild;
return true; return true;
} }

View file

@ -4174,8 +4174,16 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
// remove from guild // remove from guild
if (uint32 guildId = GetGuildIdFromDB(playerguid)) if (uint32 guildId = GetGuildIdFromDB(playerguid))
{
if (Guild* guild = sGuildMgr.GetGuildById(guildId)) if (Guild* guild = sGuildMgr.GetGuildById(guildId))
guild->DelMember(playerguid); {
if (guild->DelMember(playerguid))
{
guild->Disband();
delete guild;
}
}
}
// remove from arena teams // remove from arena teams
LeaveAllArenaTeams(playerguid); LeaveAllArenaTeams(playerguid);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "11533" #define REVISION_NR "11534"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__