From 56f1c3d984fe1b1c5c21bba3417abedcefa9213f Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 29 Nov 2021 17:09:03 -0500 Subject: [PATCH] Core/BattlePets: Implemented BattlePetSpeciesFlags::NotAccountWide Port From (https://github.com/TrinityCore/TrinityCore/commit/93c668ac50a529876054212dfef6544f70259035) --- .../Database/Databases/LoginDatabase.cs | 6 +- Source/Game/BattlePets/BattlePetManager.cs | 91 ++++++++++++++++--- Source/Game/Entities/Player/Player.DB.cs | 8 ++ Source/Game/Server/WorldSession.cs | 1 + Source/Game/Spells/SpellEffects.cs | 2 +- sql/base/auth_database.sql | 5 +- .../auth/master/2021_11_25_00_auth.sql | 3 + 7 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 sql/updates/auth/master/2021_11_25_00_auth.sql diff --git a/Source/Framework/Database/Databases/LoginDatabase.cs b/Source/Framework/Database/Databases/LoginDatabase.cs index 7dfe5d6fd..797334cb2 100644 --- a/Source/Framework/Database/Databases/LoginDatabase.cs +++ b/Source/Framework/Database/Databases/LoginDatabase.cs @@ -151,9 +151,10 @@ namespace Framework.Database PrepareStatement(LoginStatements.REP_ACCOUNT_TOYS, "REPLACE INTO battlenet_account_toys (accountId, itemId, isFavourite, hasFanfare) VALUES (?, ?, ?, ?)"); // Battle Pets - PrepareStatement(LoginStatements.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 = ?"); - PrepareStatement(LoginStatements.INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, displayId, level, exp, health, quality, flags, name, nameTimestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(LoginStatements.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 = ?)"); + PrepareStatement(LoginStatements.INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, displayId, level, exp, health, quality, flags, name, nameTimestamp, owner, ownerRealmId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(LoginStatements.DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?"); + PrepareStatement(LoginStatements.DEL_BATTLE_PETS_BY_OWNER, "DELETE FROM battle_pets WHERE owner = ? AND ownerRealmId = ?"); PrepareStatement(LoginStatements.UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ?, nameTimestamp = ? WHERE battlenetAccountId = ? AND guid = ?"); PrepareStatement(LoginStatements.SEL_BATTLE_PET_SLOTS, "SELECT id, battlePetGuid, locked FROM battle_pet_slots WHERE battlenetAccountId = ?"); PrepareStatement(LoginStatements.INS_BATTLE_PET_SLOTS, "INSERT INTO battle_pet_slots (id, battlenetAccountId, battlePetGuid, locked) VALUES (?, ?, ?, ?)"); @@ -300,6 +301,7 @@ namespace Framework.Database SEL_BATTLE_PETS, INS_BATTLE_PETS, DEL_BATTLE_PETS, + DEL_BATTLE_PETS_BY_OWNER, UPD_BATTLE_PETS, SEL_BATTLE_PET_SLOTS, INS_BATTLE_PET_SLOTS, diff --git a/Source/Game/BattlePets/BattlePetManager.cs b/Source/Game/BattlePets/BattlePetManager.cs index 9f89ba25d..6c228acc6 100644 --- a/Source/Game/BattlePets/BattlePetManager.cs +++ b/Source/Game/BattlePets/BattlePetManager.cs @@ -174,13 +174,35 @@ namespace Game.BattlePets do { uint species = petsResult.Read(1); + ObjectGuid ownerGuid = !petsResult.IsNull(11) ? ObjectGuid.Create(HighGuid.Player, petsResult.Read(11)) : ObjectGuid.Empty; BattlePetSpeciesRecord speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(species); if (speciesEntry != null) { - if (HasMaxPetCount(speciesEntry)) + if (speciesEntry.GetFlags().HasFlag(BattlePetSpeciesFlags.NotAccountWide)) { - Log.outError(LogFilter.Misc, "Battlenet account with id {0} has more than maximum battle pets of species {1}", _owner.GetBattlenetAccountId(), species); + if (ownerGuid.IsEmpty()) + { + Log.outError(LogFilter.Misc, $"Battlenet account with id {_owner.GetBattlenetAccountId()} has battle pet of species {species} with BattlePetSpeciesFlags::NotAccountWide but no owner"); + continue; + } + } + else + { + if (!ownerGuid.IsEmpty()) + { + Log.outError(LogFilter.Misc, $"Battlenet account with id {_owner.GetBattlenetAccountId()} has battle pet of species {species} without BattlePetSpeciesFlags::NotAccountWide but with owner"); + continue; + } + } + + if (HasMaxPetCount(speciesEntry, ownerGuid)) + { + if (ownerGuid.IsEmpty()) + Log.outError(LogFilter.Misc, $"Battlenet account with id {_owner.GetBattlenetAccountId()} has more than maximum battle pets of species {species}"); + else + Log.outError(LogFilter.Misc, $"Battlenet account with id {_owner.GetBattlenetAccountId()} has more than maximum battle pets of species {species} for player {ownerGuid}"); + continue; } @@ -198,11 +220,19 @@ namespace Game.BattlePets pet.NameTimestamp = petsResult.Read(10); pet.PacketInfo.CreatureID = speciesEntry.CreatureID; - if (!petsResult.IsNull(11)) + if (!petsResult.IsNull(12)) { pet.DeclinedName = new(); for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i) - pet.DeclinedName.name[i] = petsResult.Read(11 + i); + pet.DeclinedName.name[i] = petsResult.Read(12 + i); + } + + if (!ownerGuid.IsEmpty()) + { + pet.PacketInfo.OwnerInfo.HasValue = true; + pet.PacketInfo.OwnerInfo.Value.Guid = ownerGuid; + pet.PacketInfo.OwnerInfo.Value.PlayerVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress(); + pet.PacketInfo.OwnerInfo.Value.PlayerNativeRealm = Global.WorldMgr.GetVirtualRealmAddress(); } pet.SaveInfo = BattlePetSaveInfo.Unchanged; @@ -250,6 +280,17 @@ namespace Game.BattlePets stmt.AddValue(9, pair.Value.PacketInfo.Flags); stmt.AddValue(10, pair.Value.PacketInfo.Name); stmt.AddValue(11, pair.Value.NameTimestamp); + if (pair.Value.PacketInfo.OwnerInfo.HasValue) + { + stmt.AddValue(12, pair.Value.PacketInfo.OwnerInfo.Value.Guid.GetCounter()); + stmt.AddValue(13, Global.WorldMgr.GetRealmId().Index); + } + else + { + stmt.AddNull(12); + stmt.AddNull(13); + } + trans.Append(stmt); if (pair.Value.DeclinedName != null) @@ -352,7 +393,16 @@ namespace Game.BattlePets 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.HasValue = true; + pet.PacketInfo.OwnerInfo.Value.Guid = player.GetGUID(); + pet.PacketInfo.OwnerInfo.Value.PlayerVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress(); + pet.PacketInfo.OwnerInfo.Value.PlayerNativeRealm = Global.WorldMgr.GetVirtualRealmAddress(); + } + pet.SaveInfo = BattlePetSaveInfo.New; _pets[pet.PacketInfo.Guid.GetCounter()] = pet; @@ -361,8 +411,8 @@ namespace Game.BattlePets updates.Add(pet); SendUpdates(updates, true); - _owner.GetPlayer().UpdateCriteria(CriteriaType.UniquePetsOwned); - _owner.GetPlayer().UpdateCriteria(CriteriaType.LearnedNewPet, species); + player.UpdateCriteria(CriteriaType.UniquePetsOwned); + player.UpdateCriteria(CriteriaType.LearnedNewPet, species); } public void RemovePet(ObjectGuid guid) @@ -426,15 +476,29 @@ namespace Game.BattlePets return false; } - public byte GetPetCount(uint species) + public byte GetPetCount(BattlePetSpeciesRecord battlePetSpecies, ObjectGuid ownerGuid) { - return (byte)_pets.Values.Count(battlePet => battlePet.PacketInfo.Species == species && battlePet.SaveInfo != BattlePetSaveInfo.Removed); + return (byte)_pets.Values.Count(battlePet => + { + if (battlePet.PacketInfo.Species != battlePetSpecies.Id) + return false; + + if (battlePet.SaveInfo == BattlePetSaveInfo.Removed) + return false; + + if (battlePetSpecies.GetFlags().HasFlag(BattlePetSpeciesFlags.NotAccountWide)) + if (!ownerGuid.IsEmpty() && battlePet.PacketInfo.OwnerInfo.HasValue) + if (battlePet.PacketInfo.OwnerInfo.Value.Guid != ownerGuid) + return false; + + return true; + }); } - public bool HasMaxPetCount(BattlePetSpeciesRecord speciesEntry) + public bool HasMaxPetCount(BattlePetSpeciesRecord battlePetSpecies, ObjectGuid ownerGuid) { - int maxPetsPerSpecies = speciesEntry.GetFlags().HasFlag(BattlePetSpeciesFlags.LegacyAccountUnique) ? 1 : SharedConst.DefaultMaxBattlePetsPerSpecies; - return GetPetCount(speciesEntry.Id) >= maxPetsPerSpecies; + int maxPetsPerSpecies = battlePetSpecies.GetFlags().HasFlag(BattlePetSpeciesFlags.LegacyAccountUnique) ? 1 : SharedConst.DefaultMaxBattlePetsPerSpecies; + return GetPetCount(battlePetSpecies, ownerGuid) >= maxPetsPerSpecies; } public uint GetPetUniqueSpeciesCount() @@ -575,7 +639,8 @@ namespace Game.BattlePets foreach (var pet in _pets) if (pet.Value.SaveInfo != BattlePetSaveInfo.Removed) - battlePetJournal.Pets.Add(pet.Value.PacketInfo); + if (!pet.Value.PacketInfo.OwnerInfo.HasValue || pet.Value.PacketInfo.OwnerInfo.Value.Guid == _owner.GetPlayer().GetGUID()) + battlePetJournal.Pets.Add(pet.Value.PacketInfo); battlePetJournal.Slots = _slots; _owner.SendPacket(battlePetJournal); diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index acf743d4a..e947ba8f0 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3823,6 +3823,8 @@ namespace Game.Entities } SQLTransaction trans = new(); + SQLTransaction loginTransaction = new(); + ulong guildId = Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(playerGuid); if (guildId != 0) { @@ -4215,6 +4217,11 @@ namespace Game.Entities stmt.AddValue(0, guid); trans.Append(stmt); + stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BATTLE_PETS_BY_OWNER); + stmt.AddValue(0, guid); + stmt.AddValue(0, Global.WorldMgr.GetRealmId().Index); + loginTransaction.Append(stmt); + Corpse.DeleteFromDB(playerGuid, trans); Garrison.DeleteFromDB(guid, trans); @@ -4240,6 +4247,7 @@ namespace Game.Entities return; } + DB.Login.CommitTransaction(loginTransaction); DB.Characters.CommitTransaction(trans); if (updateRealmChars) diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index c25c47ce0..91d06eadc 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -1059,6 +1059,7 @@ namespace Game stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BATTLE_PETS); stmt.AddValue(0, battlenetAccountId); + stmt.AddValue(1, Global.WorldMgr.GetRealmId().Index); SetQuery(AccountInfoQueryLoad.BattlePets, stmt); stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BATTLE_PET_SLOTS); diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 44b5bb19a..bd10216a2 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5445,7 +5445,7 @@ namespace Game.Spells return; } - if (battlePetMgr.HasMaxPetCount(speciesEntry)) + if (battlePetMgr.HasMaxPetCount(speciesEntry, player.GetGUID())) { battlePetMgr.SendError(BattlePetError.CantHaveMorePetsOfThatType, speciesEntry.CreatureID); SendCastResult(SpellCastResult.CantAddBattlePet); diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 7ffaa62c9..7e6c288e0 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 000000000..7b4497180 --- /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`;