From b2c17b4881e2cef88450b3b122ce6419c4c664da Mon Sep 17 00:00:00 2001 From: Aokromes Date: Sun, 27 Nov 2016 02:41:25 +0100 Subject: [PATCH] Core/Guild: avoid data integrity problems wrapping delete+insert statements in a transaction --- src/server/game/Entities/Player/Player.cpp | 15 +- src/server/game/Guilds/Guild.cpp | 223 ++++++++++-------- src/server/game/Guilds/Guild.h | 44 ++-- src/server/game/Handlers/CharacterHandler.cpp | 7 +- src/server/game/Handlers/PetitionsHandler.cpp | 16 +- src/server/scripts/Commands/cs_guild.cpp | 9 +- 6 files changed, 171 insertions(+), 143 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 727cb0108e..2099679c10 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4259,9 +4259,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe charDelete_method = CHAR_DELETE_REMOVE; } + SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (ObjectGuid::LowType guildId = GetGuildIdFromDB(playerguid)) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->DeleteMember(playerguid, false, false, true); + guild->DeleteMember(trans, playerguid, false, false, true); // close player ticket if any GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid); @@ -4288,8 +4289,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe // Completely remove from the database case CHAR_DELETE_REMOVE: { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL); stmt->setUInt32(0, guid); PreparedQueryResult resultMail = CharacterDatabase.Query(stmt); @@ -4578,26 +4577,28 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe trans->Append(stmt); Corpse::DeleteFromDB(playerguid, trans); - - CharacterDatabase.CommitTransaction(trans); break; } // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame case CHAR_DELETE_UNLINK: { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO); - stmt->setUInt32(0, guid); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); break; } default: TC_LOG_INFO("entities.player.cheat", "Player::DeleteFromDB: Tried to delete player (%s) with unsupported delete method (%u).", playerguid.ToString().c_str(), charDelete_method); + + if (trans->GetSize() > 0) + CharacterDatabase.CommitTransaction(trans); return; } + CharacterDatabase.CommitTransaction(trans); + if (updateRealmChars) sWorld->UpdateRealmCharCount(accountId); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 48d1f4225e..754fdc7457 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -159,7 +159,7 @@ inline void Guild::LogHolder::WritePacket(WorldPacket& data) const { ByteBuffer buffer; data.WriteBits(m_log.size(), 23); - for (GuildLog::const_iterator itr = m_log.begin(); itr != m_log.end(); ++itr) + for (auto itr = m_log.begin(); itr != m_log.end(); ++itr) (*itr)->WritePacket(data, buffer); data.FlushBits(); @@ -183,7 +183,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG); stmt->setUInt32(0, m_guildId); stmt->setUInt32(1, m_guid); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); uint8 index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_EVENTLOG); @@ -194,7 +194,7 @@ void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt32(++index, m_playerGuid2); stmt->setUInt8 (++index, m_newRank); stmt->setUInt64(++index, m_timestamp); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); } void Guild::EventLogEntry::WritePacket(WorldPacket& data, ByteBuffer& content) const @@ -258,7 +258,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt32( index, m_guildId); stmt->setUInt32(++index, m_guid); stmt->setUInt8 (++index, m_bankTabId); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_EVENTLOG); @@ -271,7 +271,7 @@ void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const stmt->setUInt16(++index, m_itemStackCount); stmt->setUInt8 (++index, m_destTabId); stmt->setUInt64(++index, m_timestamp); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); } void Guild::BankEventLogEntry::WritePacket(WorldPacket& data, ByteBuffer& content) const @@ -536,14 +536,16 @@ bool Guild::BankTab::LoadItemFromDB(Field* fields) void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB) { for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + { if (Item* pItem = m_items[slotId]) { pItem->RemoveFromWorld(); if (removeItemsFromDB) pItem->DeleteFromDB(trans); delete pItem; - pItem = NULL; + pItem = nullptr; } + } } void Guild::BankTab::SetInfo(std::string const& name, std::string const& icon) @@ -578,7 +580,7 @@ void Guild::BankTab::SetText(std::string const& text) } // Sets/removes contents of specified slot. -// If pItem == NULL contents are removed. +// If pItem == nullptr contents are removed. bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) { if (slotId >= GUILD_BANK_MAX_SLOTS) @@ -590,7 +592,7 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) stmt->setUInt32(0, m_guildId); stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); if (item) { @@ -599,13 +601,14 @@ bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* item) stmt->setUInt8 (1, m_tabId); stmt->setUInt8 (2, slotId); stmt->setUInt32(3, item->GetGUID().GetCounter()); - CharacterDatabase.ExecuteOrAppend(trans, stmt); + trans->Append(stmt); item->SetGuidValue(ITEM_FIELD_CONTAINED, ObjectGuid::Empty); item->SetGuidValue(ITEM_FIELD_OWNER, ObjectGuid::Empty); item->FSetState(ITEM_NEW); item->SaveToDB(trans); // Not in inventory and can be saved standalone } + return true; } @@ -676,7 +679,7 @@ void Guild::Member::SetOfficerNote(std::string const& officerNote) CharacterDatabase.Execute(stmt); } -void Guild::Member::ChangeRank(uint8 newRank) +void Guild::Member::ChangeRank(SQLTransaction& trans, uint8 newRank) { m_rankId = newRank; @@ -687,7 +690,7 @@ void Guild::Member::ChangeRank(uint8 newRank) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_MEMBER_RANK); stmt->setUInt8 (0, newRank); stmt->setUInt32(1, m_guid.GetCounter()); - CharacterDatabase.Execute(stmt); + CharacterDatabase.ExecuteOrAppend(trans, stmt); } void Guild::Member::SaveToDB(SQLTransaction& trans) const @@ -874,7 +877,7 @@ void Guild::MoveItemData::LogAction(MoveItemData* pFrom) const inline void Guild::MoveItemData::CopySlots(SlotIds& ids) const { - for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ++itr) + for (auto itr = m_vec.begin(); itr != m_vec.end(); ++itr) ids.insert(uint8(itr->pos)); } @@ -888,16 +891,16 @@ bool Guild::PlayerMoveItemData::InitItem() if (m_pItem->IsNotEmptyBag()) { m_pPlayer->SendEquipError(EQUIP_ERR_DESTROY_NONEMPTY_BAG, m_pItem); - m_pItem = NULL; + m_pItem = nullptr; } // Bound items cannot be put into bank. else if (!m_pItem->CanBeTraded()) { m_pPlayer->SendEquipError(EQUIP_ERR_CANT_SWAP, m_pItem); - m_pItem = NULL; + m_pItem = nullptr; } } - return (m_pItem != NULL); + return (m_pItem != nullptr); } void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount) @@ -912,7 +915,7 @@ void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* { m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true); m_pItem->DeleteFromInventoryDB(trans); - m_pItem = NULL; + m_pItem = nullptr; } } @@ -979,7 +982,7 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO else { m_pGuild->_RemoveItem(trans, m_container, m_slotId); - m_pItem = NULL; + m_pItem = nullptr; } // Decrease amount of player's remaining items (if item is moved to different tab or to player) if (!pOther->IsBank() || pOther->GetContainer() != m_container) @@ -989,14 +992,14 @@ void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pO Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) { if (!pItem) - return NULL; + return nullptr; BankTab* pTab = m_pGuild->GetBankTab(m_container); if (!pTab) - return NULL; + return nullptr; Item* pLastItem = pItem; - for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ) + for (auto itr = m_vec.begin(); itr != m_vec.end(); ) { ItemPosCount pos(*itr); ++itr; @@ -1060,7 +1063,7 @@ Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab, if (pItem && pTab->SetItem(trans, slotId, pItem)) return pItem; - return NULL; + return nullptr; } // Tries to reserve space for source item. @@ -1100,10 +1103,10 @@ void Guild::BankMoveItemData::CanStoreItemInTab(Item* pItem, uint8 skipSlotId, b Item* pItemDest = m_pGuild->_GetItem(m_container, slotId); if (pItemDest == pItem) - pItemDest = NULL; + pItemDest = nullptr; // If merge skip empty, if not merge skip non-empty - if ((pItemDest != NULL) != merge) + if ((pItemDest != nullptr) != merge) continue; _ReserveSpace(slotId, pItem, pItemDest, count); @@ -1130,7 +1133,7 @@ InventoryResult Guild::BankMoveItemData::CanStore(Item* pItem, bool swap) Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId); // Ignore swapped item (this slot will be empty after move) if ((pItemDest == pItem) || swap) - pItemDest = NULL; + pItemDest = nullptr; if (!_ReserveSpace(m_slotId, pItem, pItemDest, count)) return EQUIP_ERR_CANT_STACK; @@ -1163,8 +1166,8 @@ Guild::Guild(): m_createdDate(0), m_accountsNumber(0), m_bankMoney(0), - m_eventLog(NULL), - m_newsLog(NULL), + m_eventLog(nullptr), + m_newsLog(nullptr), m_achievementMgr(this), _level(1), _experience(0), @@ -1175,25 +1178,25 @@ Guild::Guild(): Guild::~Guild() { - SQLTransaction temp(NULL); + SQLTransaction temp(nullptr); _DeleteBankItems(temp); // Cleanup delete m_eventLog; - m_eventLog = NULL; + m_eventLog = nullptr; delete m_newsLog; - m_newsLog = NULL; + m_newsLog = nullptr; for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) { delete m_bankEventLog[tabId]; - m_bankEventLog[tabId] = NULL; + m_bankEventLog[tabId] = nullptr; } - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) { delete itr->second; - itr->second = NULL; + itr->second = nullptr; } } @@ -1214,7 +1217,7 @@ bool Guild::Create(Player* pLeader, std::string const& name) m_info = ""; m_motd = "No message set."; m_bankMoney = 0; - m_createdDate = ::time(NULL); + m_createdDate = ::time(nullptr); _level = 1; _experience = 0; _todayExperience = 0; @@ -1245,9 +1248,10 @@ bool Guild::Create(Player* pLeader, std::string const& name) stmt->setUInt64(++index, m_bankMoney); trans->Append(stmt); + _CreateDefaultGuildRanks(trans, pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks + bool ret = AddMember(trans, m_leaderGuid, GR_GUILDMASTER); // Add guildmaster + CharacterDatabase.CommitTransaction(trans); - _CreateDefaultGuildRanks(pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks - bool ret = AddMember(m_leaderGuid, GR_GUILDMASTER); // Add guildmaster if (ret) { @@ -1265,15 +1269,15 @@ void Guild::Disband() sScriptMgr->OnGuildDisband(this); _BroadcastEvent(GE_DISBANDED, ObjectGuid::Empty); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); // Remove all members while (!m_members.empty()) { - Members::const_iterator itr = m_members.begin(); - DeleteMember(itr->second->GetGUID(), true); + auto itr = m_members.begin(); + DeleteMember(trans, itr->second->GetGUID(), true); } - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD); stmt->setUInt32(0, m_id); trans->Append(stmt); @@ -1678,11 +1682,8 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string return; } - char aux[2]; - sprintf(aux, "%u", tabId); - tab->SetInfo(name, icon); - _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, aux, name.c_str(), icon.c_str()); + _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, std::to_string(tabId).c_str(), name.c_str(), icon.c_str()); } void Guild::HandleSetMemberNote(WorldSession* session, std::string const& note, ObjectGuid guid, bool officer) @@ -1714,12 +1715,10 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string c rankInfo->SetRights(rights); _SetRankBankMoneyPerDay(rankId, moneyPerDay); - for (GuildBankRightsAndSlotsVec::const_iterator itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr) + for (auto itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr) _SetRankBankTabRightsAndSlots(rankId, *itr); - char aux[2]; - sprintf(aux, "%u", rankId); - _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, aux); + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId).c_str(), name.c_str()); } } @@ -1878,7 +1877,8 @@ void Guild::HandleAcceptMember(WorldSession* session) player->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(GetLeaderGUID())) return; - AddMember(player->GetGUID()); + SQLTransaction trans(nullptr); + AddMember(trans, player->GetGUID()); } void Guild::HandleLeaveMember(WorldSession* session) @@ -1903,7 +1903,8 @@ void Guild::HandleLeaveMember(WorldSession* session) } else { - DeleteMember(player->GetGUID(), false, false); + SQLTransaction trans(nullptr); + DeleteMember(trans, player->GetGUID(), false, false); _LogEvent(GUILD_EVENT_LOG_LEAVE_GUILD, player->GetGUID().GetCounter()); _BroadcastEvent(GE_LEFT, player->GetGUID(), player->GetName().c_str()); @@ -1940,7 +1941,9 @@ void Guild::HandleRemoveMember(WorldSession* session, ObjectGuid guid) else { // After call to DeleteMember pointer to member becomes invalid - DeleteMember(guid, false, true); + + SQLTransaction trans(nullptr); + DeleteMember(trans, guid, false, true); _LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUID().GetCounter(), guid.GetCounter()); _BroadcastEvent(GE_REMOVED, ObjectGuid::Empty, name.c_str(), player->GetName().c_str()); SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_COMMAND_SUCCESS, name); @@ -1996,7 +1999,8 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, ObjectGuid guid, bool } uint32 newRankId = member->GetRankId() + (demote ? 1 : -1); - member->ChangeRank(newRankId); + SQLTransaction trans(nullptr); + member->ChangeRank(trans, newRankId); _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), newRankId); _BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName().c_str(), name.c_str(), _GetRankName(newRankId).c_str()); } @@ -2040,8 +2044,11 @@ void Guild::HandleAddNewRank(WorldSession* session, std::string const& name) // Only leader can add new rank if (_IsLeader(session->GetPlayer())) - if (_CreateRank(name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) - _BroadcastEvent(GE_RANK_CREATED, ObjectGuid::Empty); + { + SQLTransaction trans(nullptr); + if (_CreateRank(trans, name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK)) + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(size).c_str(), name.c_str()); + } } void Guild::HandleRemoveRank(WorldSession* session, uint8 rankId) @@ -2424,10 +2431,11 @@ void Guild::LoadRankFromDB(Field* fields) bool Guild::LoadMemberFromDB(Field* fields) { ObjectGuid::LowType lowguid = fields[1].GetUInt32(); - Member *member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8()); + Member* member = new Member(m_id, ObjectGuid(HighGuid::Player, lowguid), fields[2].GetUInt8()); if (!member->LoadFromDB(fields)) { - _DeleteMemberFromDB(lowguid); + SQLTransaction trans(nullptr); + _DeleteMemberFromDB(trans, lowguid); delete member; return false; } @@ -2546,6 +2554,8 @@ bool Guild::Validate() // Min ranks count is 2 and max is 10. bool broken_ranks = false; uint8 ranks = _GetRanksSize(); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT) { TC_LOG_ERROR("guild", "Guild %u has invalid number of ranks, creating new...", m_id); @@ -2562,24 +2572,20 @@ bool Guild::Validate() broken_ranks = true; } else - { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); rankInfo->CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans, true); - CharacterDatabase.CommitTransaction(trans); - } } } if (broken_ranks) { m_ranks.clear(); - _CreateDefaultGuildRanks(DEFAULT_LOCALE); + _CreateDefaultGuildRanks(trans, DEFAULT_LOCALE); } // Validate members' data - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->GetRankId() > _GetRanksSize()) - itr->second->ChangeRank(_GetLowestRankId()); + itr->second->ChangeRank(trans, _GetLowestRankId()); // Repair the structure of the guild. // If the guildmaster doesn't exist or isn't member of the guild @@ -2587,7 +2593,8 @@ bool Guild::Validate() Member* pLeader = GetMember(m_leaderGuid); if (!pLeader) { - DeleteMember(m_leaderGuid); + SQLTransaction trans(nullptr); + DeleteMember(trans, m_leaderGuid); // If no more members left, disband guild if (m_members.empty()) { @@ -2600,10 +2607,12 @@ bool Guild::Validate() // Check config if multiple guildmasters are allowed if (!sConfigMgr->GetBoolDefault("Guild.AllowMultipleGuildMaster", 0)) - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->GetRankId() == GR_GUILDMASTER && !itr->second->IsSamePlayer(m_leaderGuid)) - itr->second->ChangeRank(GR_OFFICER); + itr->second->ChangeRank(trans, GR_OFFICER); + if (trans->GetSize() > 0) + CharacterDatabase.CommitTransaction(trans); _UpdateAccountsNumber(); return true; } @@ -2614,8 +2623,8 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPacket data; - ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), NULL, msg); - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID().GetCounter())) @@ -2640,7 +2649,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std:: void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->IsRank(rankId)) if (Player* player = itr->second->FindConnectedPlayer()) player->GetSession()->SendPacket(packet); @@ -2648,7 +2657,7 @@ void Guild::BroadcastPacketToRank(WorldPacket* packet, uint8 rankId) const void Guild::BroadcastPacket(WorldPacket* packet) const { - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) player->GetSession()->SendPacket(packet); } @@ -2668,7 +2677,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max WorldPacket data(SMSG_CALENDAR_FILTER_GUILD); data << uint32(count); // count placeholder - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) { // not sure if needed, maybe client checks it as well if (count >= CALENDAR_MAX_INVITES) @@ -2695,7 +2704,7 @@ void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 max } // Members handling -bool Guild::AddMember(ObjectGuid guid, uint8 rankId) +bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) { Player* player = ObjectAccessor::FindConnectedPlayer(guid); // Player cannot be in guild @@ -2760,7 +2769,6 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId) m_members[lowguid] = member; } - SQLTransaction trans(NULL); member->SaveToDB(trans); _UpdateAccountsNumber(); @@ -2774,7 +2782,7 @@ bool Guild::AddMember(ObjectGuid guid, uint8 rankId) return true; } -void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) +void Guild::DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) { ObjectGuid::LowType lowguid = guid.GetCounter(); Player* player = ObjectAccessor::FindConnectedPlayer(guid); @@ -2783,9 +2791,9 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool // or when he is removed from guild by gm command if (m_leaderGuid == guid && !isDisbanding) { - Member* oldLeader = NULL; - Member* newLeader = NULL; - for (Guild::Members::iterator i = m_members.begin(); i != m_members.end(); ++i) + Member* oldLeader = nullptr; + Member* newLeader = nullptr; + for (auto i = m_members.begin(); i != m_members.end(); ++i) { if (i->first == lowguid) oldLeader = i->second; @@ -2834,19 +2842,22 @@ void Guild::DeleteMember(ObjectGuid guid, bool isDisbanding, bool isKicked, bool player->RemoveSpell(entry->SpellId, false, false); } - _DeleteMemberFromDB(lowguid); + _DeleteMemberFromDB(trans, lowguid); if (!isDisbanding) _UpdateAccountsNumber(); } -bool Guild::ChangeMemberRank(ObjectGuid guid, uint8 newRank) +bool Guild::ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank) { if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks) + { if (Member* member = GetMember(guid)) { - member->ChangeRank(newRank); + member->ChangeRank(trans, newRank); return true; } + } + return false; } @@ -2890,7 +2901,7 @@ void Guild::SetBankTabText(uint8 tabId, std::string const& text) if (BankTab* pTab = GetBankTab(tabId)) { pTab->SetText(text); - pTab->SendText(this, NULL); + pTab->SendText(this, nullptr); } } @@ -2921,30 +2932,32 @@ void Guild::_CreateNewBankTab() trans->Append(stmt); ++tabId; - for (Ranks::iterator itr = m_ranks.begin(); itr != m_ranks.end(); ++itr) + for (auto itr = m_ranks.begin(); itr != m_ranks.end(); ++itr) (*itr).CreateMissingTabsIfNeeded(tabId, trans, false); CharacterDatabase.CommitTransaction(trans); } -void Guild::_CreateDefaultGuildRanks(LocaleConstant loc) +void Guild::_CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc) { + ASSERT(trans); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); stmt->setUInt32(0, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS); stmt->setUInt32(0, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - _CreateRank(sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); } -bool Guild::_CreateRank(std::string const& name, uint32 rights) +bool Guild::_CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights) { uint8 newRankId = _GetRanksSize(); if (newRankId >= GUILD_RANKS_MAX_COUNT) @@ -2954,10 +2967,15 @@ bool Guild::_CreateRank(std::string const& name, uint32 rights) RankInfo info(m_id, newRankId, name, rights, 0); m_ranks.push_back(info); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); + bool const isInTransaction = bool(trans); + if (!isInTransaction) + trans = CharacterDatabase.BeginTransaction(); + info.CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans); info.SaveToDB(trans); - CharacterDatabase.CommitTransaction(trans); + + if (!isInTransaction) + CharacterDatabase.CommitTransaction(trans); return true; } @@ -2968,7 +2986,7 @@ void Guild::_UpdateAccountsNumber() { // We use a set to be sure each element will be unique std::set accountsIdSet; - for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) accountsIdSet.insert(itr->second->GetAccountId()); m_accountsNumber = accountsIdSet.size(); @@ -2992,7 +3010,7 @@ void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB) { m_bankTabs[tabId]->Delete(trans, removeItemsFromDB); delete m_bankTabs[tabId]; - m_bankTabs[tabId] = NULL; + m_bankTabs[tabId] = nullptr; } m_bankTabs.clear(); } @@ -3021,13 +3039,16 @@ void Guild::_SetLeaderGUID(Member* pLeader) if (!pLeader) return; + SQLTransaction trans = CharacterDatabase.BeginTransaction(); m_leaderGuid = pLeader->GetGUID(); - pLeader->ChangeRank(GR_GUILDMASTER); + pLeader->ChangeRank(trans, GR_GUILDMASTER); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_LEADER); stmt->setUInt32(0, m_leaderGuid.GetCounter()); stmt->setUInt32(1, m_id); - CharacterDatabase.Execute(stmt); + trans->Append(stmt); + + CharacterDatabase.CommitTransaction(trans); } void Guild::_SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay) @@ -3175,13 +3196,13 @@ inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const { if (const BankTab* tab = GetBankTab(tabId)) return tab->GetItem(slotId); - return NULL; + return nullptr; } inline void Guild::_RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId) { if (BankTab* pTab = GetBankTab(tabId)) - pTab->SetItem(trans, slotId, NULL); + pTab->SetItem(trans, slotId, nullptr); } void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount) @@ -3222,7 +3243,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm } else // 6. No split { - // 6.1. Try to merge items in destination (pDest->GetItem() == NULL) + // 6.1. Try to merge items in destination (pDest->GetItem() == nullptr) if (!_DoItemsMove(pSrc, pDest, false)) // Item could not be merged { // 6.2. Try to swap items @@ -3237,7 +3258,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm if (!pDest->HasWithdrawRights(pSrc)) return; // Player has no rights to withdraw item from destination (opposite direction) - // 6.2.3. Swap items (pDest->GetItem() != NULL) + // 6.2.3. Swap items (pDest->GetItem() != nullptr) _DoItemsMove(pSrc, pDest, true); } } @@ -3248,7 +3269,7 @@ void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAm bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount) { Item* pDestItem = pDest->GetItem(); - bool swap = (pDestItem != NULL); + bool swap = (pDestItem != nullptr); Item* pSrcItem = pSrc->GetItem(splitedAmount != 0); // 1. Can store source item in destination diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 32f2c3996a..d233139fd2 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -401,9 +401,9 @@ private: bool IsTrackingCriteriaId(uint32 criteriaId) const { return m_trackedCriteriaIds.find(criteriaId) != m_trackedCriteriaIds.end(); } - void ChangeRank(uint8 newRank); + void ChangeRank(SQLTransaction& trans, uint8 newRank); - inline void UpdateLogoutTime() { m_logoutTime = ::time(NULL); } + inline void UpdateLogoutTime() { m_logoutTime = ::time(nullptr); } inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; } inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; } inline bool IsSamePlayer(ObjectGuid guid) const { return m_guid == guid; } @@ -853,9 +853,9 @@ public: void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank); template - void BroadcastWorker(Do& _do, Player* except = NULL) + void BroadcastWorker(Do& _do, Player* except = nullptr) { - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) if (player != except) _do(player); @@ -863,9 +863,9 @@ public: // Members // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. - bool AddMember(ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); - void DeleteMember(ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); - bool ChangeMemberRank(ObjectGuid guid, uint8 newRank); + bool AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); + void DeleteMember(SQLTransaction& trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); + bool ChangeMemberRank(SQLTransaction& trans, ObjectGuid guid, uint8 newRank); bool IsMember(ObjectGuid guid) const; uint32 GetMembersCount() { return m_members.size(); } @@ -921,8 +921,8 @@ protected: private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } - inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } - inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } + inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } + inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } inline bool _HasRankRight(Player const* player, uint32 right) const { if (player) @@ -934,35 +934,35 @@ private: inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); } - inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } - inline const BankTab* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } + inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; } + inline BankTab const* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : nullptr; } - inline const Member* GetMember(ObjectGuid guid) const + inline Member const* GetMember(ObjectGuid guid) const { - Members::const_iterator itr = m_members.find(guid.GetCounter()); - return itr != m_members.end() ? itr->second : NULL; + auto itr = m_members.find(guid.GetCounter()); + return itr != m_members.end() ? itr->second : nullptr; } inline Member* GetMember(ObjectGuid guid) { - Members::iterator itr = m_members.find(guid.GetCounter()); - return itr != m_members.end() ? itr->second : NULL; + auto itr = m_members.find(guid.GetCounter()); + return itr != m_members.end() ? itr->second : nullptr; } inline Member* GetMember(std::string const& name) { - for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) if (itr->second->GetName() == name) return itr->second; - return NULL; + return nullptr; } - inline void _DeleteMemberFromDB(ObjectGuid::LowType lowguid) const + inline void _DeleteMemberFromDB(SQLTransaction& trans, ObjectGuid::LowType lowguid) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); stmt->setUInt32(0, lowguid); - CharacterDatabase.Execute(stmt); + CharacterDatabase.ExecuteOrAppend(trans, stmt); } // Creates log holders (either when loading or when creating guild) @@ -970,9 +970,9 @@ private: // Tries to create new bank tab void _CreateNewBankTab(); // Creates default guild ranks with names in given locale - void _CreateDefaultGuildRanks(LocaleConstant loc); + void _CreateDefaultGuildRanks(SQLTransaction& trans, LocaleConstant loc); // Creates new rank - bool _CreateRank(std::string const& name, uint32 rights); + bool _CreateRank(SQLTransaction& trans, std::string const& name, uint32 rights); // Update account number when member added/removed from guild void _UpdateAccountsNumber(); bool _IsLeader(Player* player) const; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 765af828e8..e155cefad3 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1948,13 +1948,10 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) { // Reset guild stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); - stmt->setUInt32(0, lowGuid); - - PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (result) + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32())) - guild->DeleteMember(factionChangeInfo.Guid, false, false, true); + guild->DeleteMember(trans, factionChangeInfo.Guid, false, false, true); Player::LeaveAllArenaTeams(factionChangeInfo.Guid); } diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index b11f089410..f5eb911003 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -845,12 +845,18 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData) Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_COMMAND_SUCCESS, name); - // Add members from signatures - for (uint8 i = 0; i < signatures; ++i) { - Field* fields = result->Fetch(); - guild->AddMember(ObjectGuid(HighGuid::Player, fields[0].GetUInt32())); - result->NextRow(); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + // Add members from signatures + for (uint8 i = 0; i < signatures; ++i) + { + Field* fields = result->Fetch(); + guild->AddMember(trans, ObjectGuid(HighGuid::Player, fields[0].GetUInt32())); + result->NextRow(); + } + + CharacterDatabase.CommitTransaction(trans); } } else diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 602497b24f..8635a5e7d4 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -148,7 +148,8 @@ public: return false; // player's guild membership checked in AddMember before add - return targetGuild->AddMember(targetGuid); + SQLTransaction trans(nullptr); + return targetGuild->AddMember(trans, targetGuid); } static bool HandleGuildUninviteCommand(ChatHandler* handler, char const* args) @@ -166,7 +167,8 @@ public: if (!targetGuild) return false; - targetGuild->DeleteMember(targetGuid, false, true, true); + SQLTransaction trans(nullptr); + targetGuild->DeleteMember(trans, targetGuid, false, true, true); return true; } @@ -193,7 +195,8 @@ public: return false; uint8 newRank = uint8(atoi(rankStr)); - return targetGuild->ChangeMemberRank(targetGuid, newRank); + SQLTransaction trans(nullptr); + return targetGuild->ChangeMemberRank(trans, targetGuid, newRank); } static bool HandleGuildRenameCommand(ChatHandler* handler, char const* _args)