aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/auth_database.sql5
-rw-r--r--sql/updates/auth/master/2021_11_25_00_auth.sql3
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp5
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h1
-rw-r--r--src/server/game/BattlePets/BattlePetMgr.cpp89
-rw-r--r--src/server/game/BattlePets/BattlePetMgr.h4
-rw-r--r--src/server/game/Entities/Player/Player.cpp9
-rw-r--r--src/server/game/Server/WorldSession.cpp1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
9 files changed, 99 insertions, 20 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql
index 7ffaa62c90d..7e6c288e045 100644
--- a/sql/base/auth_database.sql
+++ b/sql/base/auth_database.sql
@@ -272,6 +272,8 @@ CREATE TABLE `battle_pets` (
`flags` smallint(5) NOT NULL DEFAULT '0',
`name` varchar(12) NOT NULL,
`nameTimestamp` bigint(20) NOT NULL DEFAULT '0',
+ `owner` bigint(20) DEFAULT NULL,
+ `ownerRealmId` int(11) DEFAULT NULL,
PRIMARY KEY (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2457,7 +2459,8 @@ INSERT INTO `updates` VALUES
('2021_11_12_00_auth.sql','012C088794362FE57BAEA0C3BD05356B40289028','ARCHIVED','2021-11-12 12:17:24',0),
('2021_11_17_00_auth.sql','298DA8468B30042B15FA17A90325C72879DF6D8E','ARCHIVED','2021-11-17 13:23:17',0),
('2021_11_19_00_auth.sql','BE4F77E254D76A59DBF28B2CEEA5CAF6777B650E','RELEASED','2021-11-19 00:37:56',0),
-('2021_11_20_00_auth.sql','E476B6DAD9C47FC81E1DA5016DC79AB527F1847A','RELEASED','2021-11-20 18:40:53',0);
+('2021_11_20_00_auth.sql','E476B6DAD9C47FC81E1DA5016DC79AB527F1847A','RELEASED','2021-11-20 18:40:53',0),
+('2021_11_25_00_auth.sql','7A01CEB201CB825BFD565BBF5EED0162BEA733E7','RELEASED','2021-11-25 19:32:21',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/auth/master/2021_11_25_00_auth.sql b/sql/updates/auth/master/2021_11_25_00_auth.sql
new file mode 100644
index 00000000000..7b4497180b5
--- /dev/null
+++ b/sql/updates/auth/master/2021_11_25_00_auth.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `battle_pets`
+ ADD `owner` bigint(20) DEFAULT NULL AFTER `nameTimestamp`,
+ ADD `ownerRealmId` int(11) DEFAULT NULL AFTER `owner`;
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index c31e8363c46..4bf91bfef89 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -155,9 +155,10 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_REP_ACCOUNT_TOYS, "REPLACE INTO battlenet_account_toys (accountId, itemId, isFavourite, hasFanfare) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
// Battle Pets
- PrepareStatement(LOGIN_SEL_BATTLE_PETS, "SELECT bp.guid, bp.species, bp.breed, bp.displayId, bp.level, bp.exp, bp.health, bp.quality, bp.flags, bp.name, bp.nameTimestamp, dn.genitive, dn.dative, dn.accusative, dn.instrumental, dn.prepositional FROM battle_pets bp LEFT JOIN battle_pet_declinedname dn ON bp.guid = dn.guid WHERE bp.battlenetAccountId = ?", CONNECTION_ASYNC);
- PrepareStatement(LOGIN_INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, displayId, level, exp, health, quality, flags, name, nameTimestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_BATTLE_PETS, "SELECT bp.guid, bp.species, bp.breed, bp.displayId, bp.level, bp.exp, bp.health, bp.quality, bp.flags, bp.name, bp.nameTimestamp, bp.owner, dn.genitive, dn.dative, dn.accusative, dn.instrumental, dn.prepositional FROM battle_pets bp LEFT JOIN battle_pet_declinedname dn ON bp.guid = dn.guid WHERE bp.battlenetAccountId = ? AND (bp.ownerRealmId IS NULL OR bp.ownerRealmId = ?)", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, displayId, level, exp, health, quality, flags, name, nameTimestamp, owner, ownerRealmId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_DEL_BATTLE_PETS_BY_OWNER, "DELETE FROM battle_pets WHERE owner = ? AND ownerRealmId = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ?, nameTimestamp = ? WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BATTLE_PET_SLOTS, "SELECT id, battlePetGuid, locked FROM battle_pet_slots WHERE battlenetAccountId = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_BATTLE_PET_SLOTS, "INSERT INTO battle_pet_slots (id, battlenetAccountId, battlePetGuid, locked) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h
index 4713600e970..130419b467e 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.h
+++ b/src/server/database/Database/Implementation/LoginDatabase.h
@@ -147,6 +147,7 @@ enum LoginDatabaseStatements : uint32
LOGIN_SEL_BATTLE_PETS,
LOGIN_INS_BATTLE_PETS,
LOGIN_DEL_BATTLE_PETS,
+ LOGIN_DEL_BATTLE_PETS_BY_OWNER,
LOGIN_UPD_BATTLE_PETS,
LOGIN_SEL_BATTLE_PET_SLOTS,
LOGIN_INS_BATTLE_PET_SLOTS,
diff --git a/src/server/game/BattlePets/BattlePetMgr.cpp b/src/server/game/BattlePets/BattlePetMgr.cpp
index 811361d223a..79754f190aa 100644
--- a/src/server/game/BattlePets/BattlePetMgr.cpp
+++ b/src/server/game/BattlePets/BattlePetMgr.cpp
@@ -26,6 +26,7 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
+#include "Realm.h"
#include "World.h"
#include "WorldSession.h"
@@ -216,12 +217,34 @@ void BattlePetMgr::LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slot
{
Field* fields = pets->Fetch();
uint32 species = fields[1].GetUInt32();
+ ObjectGuid ownerGuid = !fields[11].IsNull() ? ObjectGuid::Create<HighGuid::Player>(fields[11].GetInt64()) : ObjectGuid::Empty;
if (BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(species))
{
- if (HasMaxPetCount(speciesEntry))
+ if (speciesEntry->GetFlags().HasFlag(BattlePetSpeciesFlags::NotAccountWide))
{
- TC_LOG_ERROR("misc", "Battlenet account with id %u has more than maximum battle pets of species %u", _owner->GetBattlenetAccountId(), species);
+ if (ownerGuid.IsEmpty())
+ {
+ TC_LOG_ERROR("misc", "Battlenet account with id %u has battle pet of species %u with BattlePetSpeciesFlags::NotAccountWide but no owner", _owner->GetBattlenetAccountId(), species);
+ continue;
+ }
+ }
+ else
+ {
+ if (!ownerGuid.IsEmpty())
+ {
+ TC_LOG_ERROR("misc", "Battlenet account with id %u has battle pet of species %u without BattlePetSpeciesFlags::NotAccountWide but with owner", _owner->GetBattlenetAccountId(), species);
+ continue;
+ }
+ }
+
+ if (HasMaxPetCount(speciesEntry, ownerGuid))
+ {
+ if (ownerGuid.IsEmpty())
+ TC_LOG_ERROR("misc", "Battlenet account with id %u has more than maximum battle pets of species %u", _owner->GetBattlenetAccountId(), species);
+ else
+ TC_LOG_ERROR("misc", "Battlenet account with id %u has more than maximum battle pets of species %u for player %s", _owner->GetBattlenetAccountId(), species, ownerGuid.ToString().c_str());
+
continue;
}
@@ -239,11 +262,18 @@ void BattlePetMgr::LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slot
pet.NameTimestamp = fields[10].GetInt64();
pet.PacketInfo.CreatureID = speciesEntry->CreatureID;
- if (!fields[11].IsNull())
+ if (!fields[12].IsNull())
{
pet.DeclinedName = std::make_unique<DeclinedName>();
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- pet.DeclinedName->name[i] = fields[11 + i].GetString();
+ pet.DeclinedName->name[i] = fields[12 + i].GetString();
+ }
+
+ if (!ownerGuid.IsEmpty())
+ {
+ pet.PacketInfo.OwnerInfo.emplace();
+ pet.PacketInfo.OwnerInfo->Guid = ownerGuid;
+ pet.PacketInfo.OwnerInfo->PlayerVirtualRealm = pet.PacketInfo.OwnerInfo->PlayerNativeRealm = GetVirtualRealmAddress();
}
pet.SaveInfo = BATTLE_PET_UNCHANGED;
@@ -292,6 +322,17 @@ void BattlePetMgr::SaveToDB(LoginDatabaseTransaction& trans)
stmt->setUInt16(9, itr->second.PacketInfo.Flags);
stmt->setString(10, itr->second.PacketInfo.Name);
stmt->setInt64(11, itr->second.NameTimestamp);
+ if (itr->second.PacketInfo.OwnerInfo)
+ {
+ stmt->setInt64(12, itr->second.PacketInfo.OwnerInfo->Guid.GetCounter());
+ stmt->setInt32(13, realm.Id.Realm);
+ }
+ else
+ {
+ stmt->setNull(12);
+ stmt->setNull(13);
+ }
+
trans->Append(stmt);
if (itr->second.DeclinedName)
@@ -399,7 +440,15 @@ void BattlePetMgr::AddPet(uint32 species, uint32 display, uint16 breed, BattlePe
pet.PacketInfo.Name = "";
pet.CalculateStats();
pet.PacketInfo.Health = pet.PacketInfo.MaxHealth;
- pet.NameTimestamp = 0;
+
+ Player* player = _owner->GetPlayer();
+ if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::NotAccountWide))
+ {
+ pet.PacketInfo.OwnerInfo.emplace();
+ pet.PacketInfo.OwnerInfo->Guid = player->GetGUID();
+ pet.PacketInfo.OwnerInfo->PlayerVirtualRealm = pet.PacketInfo.OwnerInfo->PlayerNativeRealm = GetVirtualRealmAddress();
+ }
+
pet.SaveInfo = BATTLE_PET_NEW;
_pets[pet.PacketInfo.Guid.GetCounter()] = std::move(pet);
@@ -408,8 +457,8 @@ void BattlePetMgr::AddPet(uint32 species, uint32 display, uint16 breed, BattlePe
updates.push_back(std::ref(pet));
SendUpdates(std::move(updates), true);
- _owner->GetPlayer()->UpdateCriteria(CriteriaType::UniquePetsOwned);
- _owner->GetPlayer()->UpdateCriteria(CriteriaType::LearnedNewPet, species);
+ player->UpdateCriteria(CriteriaType::UniquePetsOwned);
+ player->UpdateCriteria(CriteriaType::LearnedNewPet, species);
}
void BattlePetMgr::RemovePet(ObjectGuid guid)
@@ -473,19 +522,30 @@ bool BattlePetMgr::IsPetInSlot(ObjectGuid guid)
return false;
}
-uint8 BattlePetMgr::GetPetCount(uint32 species) const
+uint8 BattlePetMgr::GetPetCount(BattlePetSpeciesEntry const* battlePetSpecies, ObjectGuid ownerGuid) const
{
- return uint8(std::count_if(_pets.begin(), _pets.end(), [species](std::pair<uint64 const, BattlePet> const& pet)
+ return uint8(std::count_if(_pets.begin(), _pets.end(), [battlePetSpecies, ownerGuid](std::pair<uint64 const, BattlePet> const& pet)
{
- return pet.second.PacketInfo.Species == species && pet.second.SaveInfo != BATTLE_PET_REMOVED;
+ if (pet.second.PacketInfo.Species != battlePetSpecies->ID)
+ return false;
+
+ if (pet.second.SaveInfo == BATTLE_PET_REMOVED)
+ return false;
+
+ if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::NotAccountWide))
+ if (!ownerGuid.IsEmpty() && pet.second.PacketInfo.OwnerInfo)
+ if (pet.second.PacketInfo.OwnerInfo->Guid != ownerGuid)
+ return false;
+
+ return true;
}));
}
-bool BattlePetMgr::HasMaxPetCount(BattlePetSpeciesEntry const* speciesEntry) const
+bool BattlePetMgr::HasMaxPetCount(BattlePetSpeciesEntry const* battlePetSpecies, ObjectGuid ownerGuid) const
{
- uint8 maxPetsPerSpecies = speciesEntry->GetFlags().HasFlag(BattlePetSpeciesFlags::LegacyAccountUnique) ? 1 : DEFAULT_MAX_BATTLE_PETS_PER_SPECIES;
+ uint8 maxPetsPerSpecies = battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::LegacyAccountUnique) ? 1 : DEFAULT_MAX_BATTLE_PETS_PER_SPECIES;
- return GetPetCount(speciesEntry->ID) >= maxPetsPerSpecies;
+ return GetPetCount(battlePetSpecies, ownerGuid) >= maxPetsPerSpecies;
}
uint32 BattlePetMgr::GetPetUniqueSpeciesCount() const
@@ -624,7 +684,8 @@ void BattlePetMgr::SendJournal()
for (auto& pet : _pets)
if (pet.second.SaveInfo != BATTLE_PET_REMOVED)
- battlePetJournal.Pets.push_back(std::ref(pet.second.PacketInfo));
+ if (!pet.second.PacketInfo.OwnerInfo || pet.second.PacketInfo.OwnerInfo->Guid == _owner->GetPlayer()->GetGUID())
+ battlePetJournal.Pets.push_back(std::ref(pet.second.PacketInfo));
battlePetJournal.Slots.reserve(_slots.size());
std::transform(_slots.begin(), _slots.end(), std::back_inserter(battlePetJournal.Slots), [](WorldPackets::BattlePet::BattlePetSlot& slot) { return std::ref(slot); });
diff --git a/src/server/game/BattlePets/BattlePetMgr.h b/src/server/game/BattlePets/BattlePetMgr.h
index 61da473d7e8..290a070cdbd 100644
--- a/src/server/game/BattlePets/BattlePetMgr.h
+++ b/src/server/game/BattlePets/BattlePetMgr.h
@@ -141,8 +141,8 @@ public:
void ModifyName(ObjectGuid guid, std::string const& name, DeclinedName* declinedName);
bool IsPetInSlot(ObjectGuid guid);
- uint8 GetPetCount(uint32 species) const;
- bool HasMaxPetCount(BattlePetSpeciesEntry const* speciesEntry) const;
+ uint8 GetPetCount(BattlePetSpeciesEntry const* battlePetSpecies, ObjectGuid ownerGuid) const;
+ bool HasMaxPetCount(BattlePetSpeciesEntry const* battlePetSpecies, ObjectGuid ownerGuid) const;
uint32 GetPetUniqueSpeciesCount() const;
WorldPackets::BattlePet::BattlePetSlot* GetSlot(uint8 slot) { return slot < _slots.size() ? &_slots[slot] : nullptr; }
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 1ad72f2b346..dadb97c39a3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3801,6 +3801,9 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
charDeleteMethod = CHAR_DELETE_REMOVE;
}
+ LoginDatabaseTransaction loginTransaction = LoginDatabase.BeginTransaction();
+ LoginDatabasePreparedStatement* loginStmt = nullptr;
+
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
if (ObjectGuid::LowType guildId = sCharacterCache->GetCharacterGuildIdByGuid(playerguid))
if (Guild* guild = sGuildMgr->GetGuildById(guildId))
@@ -4195,6 +4198,11 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt64(0, guid);
trans->Append(stmt);
+ loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BATTLE_PETS_BY_OWNER);
+ loginStmt->setInt64(0, guid);
+ loginStmt->setInt32(0, realm.Id.Realm);
+ loginTransaction->Append(loginStmt);
+
Corpse::DeleteFromDB(playerguid, trans);
Garrison::DeleteFromDB(guid, trans);
@@ -4220,6 +4228,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
return;
}
+ LoginDatabase.CommitTransaction(loginTransaction);
CharacterDatabase.CommitTransaction(trans);
if (updateRealmChars)
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 1552730bfb0..1f34512a9b6 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -1048,6 +1048,7 @@ public:
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BATTLE_PETS);
stmt->setUInt32(0, battlenetAccountId);
+ stmt->setInt32(1, realm.Id.Realm);
ok = SetPreparedQuery(BATTLE_PETS, stmt) && ok;
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BATTLE_PET_SLOTS);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index ca60210a8ba..e4930d40296 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5669,7 +5669,7 @@ void Spell::EffectUncageBattlePet()
return;
}
- if (battlePetMgr->HasMaxPetCount(speciesEntry))
+ if (battlePetMgr->HasMaxPetCount(speciesEntry, player->GetGUID()))
{
battlePetMgr->SendError(BattlePetError::CantHaveMorePetsOfType, speciesEntry->CreatureID);
SendCastResult(SPELL_FAILED_CANT_ADD_BATTLE_PET);