diff --git a/Source/Framework/Constants/BattlePetConst.cs b/Source/Framework/Constants/BattlePetConst.cs
index cde907569..0761c34bb 100644
--- a/Source/Framework/Constants/BattlePetConst.cs
+++ b/Source/Framework/Constants/BattlePetConst.cs
@@ -14,31 +14,24 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+using System;
namespace Framework.Constants
{
+ [Flags]
+ public enum BattlePetError
+ {
+ CantHaveMorePetsOfThatType = 3, // You can't have any more pets of that type.
+ CantHaveMorePets = 4, // You can't have any more pets.
+ TooHighLevelToUncage = 7, // This pet is too high level for you to uncage.
+ }
+
public enum FlagsControlType
{
Apply = 1,
Remove = 2
}
- public enum BattlePetError
- {
- CantHaveMorePetsOfThatType = 3,
- CantHaveMorePets = 4,
- TooHighLevelToUncage = 7,
-
- // TODO: find correct values if possible and needed (also wrong order)
- DuplicateConvertedPet,
- NeedToUnlock,
- BadParam,
- LockedPetAlreadyExists,
- Ok,
- Uncapturable,
- CantInvalidCharacterGuid
- }
-
// taken from BattlePetState.db2 - it seems to store some initial values for battle pets
// there are only values used in BattlePetSpeciesState.db2 and BattlePetBreedState.db2
// TODO: expand this enum if needed
diff --git a/Source/Framework/Database/Databases/LoginDatabase.cs b/Source/Framework/Database/Databases/LoginDatabase.cs
index 1cb306469..7dfe5d6fd 100644
--- a/Source/Framework/Database/Databases/LoginDatabase.cs
+++ b/Source/Framework/Database/Databases/LoginDatabase.cs
@@ -151,10 +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, 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) 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, 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.DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?");
- PrepareStatement(LoginStatements.UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ? WHERE battlenetAccountId = ? AND guid = ?");
+ 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 (?, ?, ?, ?)");
PrepareStatement(LoginStatements.DEL_BATTLE_PET_SLOTS, "DELETE FROM battle_pet_slots WHERE battlenetAccountId = ?");
diff --git a/Source/Game/BattlePets/BattlePetManager.cs b/Source/Game/BattlePets/BattlePetManager.cs
index f01feb5aa..485baa5f3 100644
--- a/Source/Game/BattlePets/BattlePetManager.cs
+++ b/Source/Game/BattlePets/BattlePetManager.cs
@@ -195,13 +195,14 @@ namespace Game.BattlePets
pet.PacketInfo.Quality = petsResult.Read(7);
pet.PacketInfo.Flags = petsResult.Read(8);
pet.PacketInfo.Name = petsResult.Read(9);
+ pet.NameTimestamp = petsResult.Read(10);
pet.PacketInfo.CreatureID = speciesEntry.CreatureID;
- if (!petsResult.IsNull(10))
+ if (!petsResult.IsNull(11))
{
pet.DeclinedName = new();
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
- pet.DeclinedName.name[i] = petsResult.Read(10 + i);
+ pet.DeclinedName.name[i] = petsResult.Read(11 + i);
}
pet.SaveInfo = BattlePetSaveInfo.Unchanged;
@@ -248,6 +249,7 @@ namespace Game.BattlePets
stmt.AddValue(8, pair.Value.PacketInfo.Quality);
stmt.AddValue(9, pair.Value.PacketInfo.Flags);
stmt.AddValue(10, pair.Value.PacketInfo.Name);
+ stmt.AddValue(11, pair.Value.NameTimestamp);
trans.Append(stmt);
if (pair.Value.DeclinedName != null)
@@ -272,8 +274,9 @@ namespace Game.BattlePets
stmt.AddValue(3, pair.Value.PacketInfo.Quality);
stmt.AddValue(4, pair.Value.PacketInfo.Flags);
stmt.AddValue(5, pair.Value.PacketInfo.Name);
- stmt.AddValue(6, _owner.GetBattlenetAccountId());
- stmt.AddValue(7, pair.Key);
+ stmt.AddValue(6, pair.Value.NameTimestamp);
+ stmt.AddValue(7, _owner.GetBattlenetAccountId());
+ stmt.AddValue(8, pair.Key);
trans.Append(stmt);
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BATTLE_PET_DECLINED_NAME);
@@ -349,6 +352,7 @@ namespace Game.BattlePets
pet.PacketInfo.Name = "";
pet.CalculateStats();
pet.PacketInfo.Health = pet.PacketInfo.MaxHealth;
+ pet.NameTimestamp = 0;
pet.SaveInfo = BattlePetSaveInfo.New;
_pets[pet.PacketInfo.Guid.GetCounter()] = pet;
@@ -395,6 +399,7 @@ namespace Game.BattlePets
return;
pet.PacketInfo.Name = name;
+ pet.NameTimestamp = !pet.PacketInfo.Name.IsEmpty() ? GameTime.GetGameTime() : 0;
pet.DeclinedName = new DeclinedName();
if (declinedName != null)
@@ -402,6 +407,14 @@ namespace Game.BattlePets
if (pet.SaveInfo != BattlePetSaveInfo.New)
pet.SaveInfo = BattlePetSaveInfo.Changed;
+
+ // Update the timestamp if the battle pet is summoned
+ Player player = _owner.GetPlayer();
+ Creature summonedBattlePet = ObjectAccessor.GetCreatureOrPetOrVehicle(player, player.GetCritterGUID());
+ if (summonedBattlePet != null)
+ if (player.GetSummonedBattlePetGUID() == summonedBattlePet.GetBattlePetCompanionGUID())
+ if (summonedBattlePet.GetBattlePetCompanionGUID() == guid)
+ summonedBattlePet.SetBattlePetCompanionNameTimestamp((uint)pet.NameTimestamp);
}
bool IsPetInSlot(ObjectGuid guid)
@@ -533,20 +546,21 @@ namespace Game.BattlePets
return;
// TODO: set proper CreatureID for spell DEFAULT_SUMMON_BATTLE_PET_SPELL (default EffectMiscValueA is 40721 - Murkimus the Gladiator)
- _owner.GetPlayer().SetSummonedBattlePetGUID(guid);
- _owner.GetPlayer().SetCurrentBattlePetBreedQuality(pet.PacketInfo.Quality);
- _owner.GetPlayer().CastSpell(_owner.GetPlayer(), speciesEntry.SummonSpellID != 0 ? speciesEntry.SummonSpellID : SharedConst.DefaultSummonBattlePetSpell);
+ Player player = _owner.GetPlayer();
+ player.SetSummonedBattlePetGUID(guid);
+ player.SetCurrentBattlePetBreedQuality(pet.PacketInfo.Quality);
+ player.CastSpell(_owner.GetPlayer(), speciesEntry.SummonSpellID != 0 ? speciesEntry.SummonSpellID : SharedConst.DefaultSummonBattlePetSpell);
}
public void DismissPet()
{
- Player ownerPlayer = _owner.GetPlayer();
- Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(ownerPlayer, ownerPlayer.GetCritterGUID());
- if (pet && ownerPlayer.m_activePlayerData.SummonedBattlePetGUID == pet.GetBattlePetCompanionGUID())
+ Player player = _owner.GetPlayer();
+ Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(player, player.GetCritterGUID());
+ if (pet && player.GetSummonedBattlePetGUID() == pet.GetBattlePetCompanionGUID())
{
pet.DespawnOrUnsummon();
- ownerPlayer.SetSummonedBattlePetGUID(ObjectGuid.Empty);
- ownerPlayer.SetCurrentBattlePetBreedQuality((byte)BattlePetBreedQuality.Poor);
+ player.SetSummonedBattlePetGUID(ObjectGuid.Empty);
+ player.SetCurrentBattlePetBreedQuality((byte)BattlePetBreedQuality.Poor);
}
}
@@ -669,6 +683,7 @@ namespace Game.BattlePets
}
public BattlePetStruct PacketInfo;
+ public long NameTimestamp;
public DeclinedName DeclinedName;
public BattlePetSaveInfo SaveInfo;
}
diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs
index 068a5c18e..54809158b 100644
--- a/Source/Game/Entities/Player/Player.cs
+++ b/Source/Game/Entities/Player/Player.cs
@@ -7444,6 +7444,7 @@ namespace Game.Entities
}
public void ClearSelfResSpell() { ClearDynamicUpdateFieldValues(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SelfResSpells)); }
+ public ObjectGuid GetSummonedBattlePetGUID() { return m_activePlayerData.SummonedBattlePetGUID; }
public void SetSummonedBattlePetGUID(ObjectGuid guid) { SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.SummonedBattlePetGUID), guid); }
public void AddTrackCreatureFlag(uint flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TrackCreatureMask), flags); }
diff --git a/Source/Game/Entities/Unit/Unit.Pets.cs b/Source/Game/Entities/Unit/Unit.Pets.cs
index b1cd34625..7e9dd5d80 100644
--- a/Source/Game/Entities/Unit/Unit.Pets.cs
+++ b/Source/Game/Entities/Unit/Unit.Pets.cs
@@ -147,10 +147,11 @@ namespace Game.Entities
Player thisPlayer = ToPlayer();
if (thisPlayer != null)
{
- var pet = thisPlayer.GetSession().GetBattlePetMgr().GetPet(thisPlayer.m_activePlayerData.SummonedBattlePetGUID);
+ var pet = thisPlayer.GetSession().GetBattlePetMgr().GetPet(thisPlayer.GetSummonedBattlePetGUID());
if (pet != null)
{
- minion.SetBattlePetCompanionGUID(thisPlayer.m_activePlayerData.SummonedBattlePetGUID);
+ minion.SetBattlePetCompanionGUID(thisPlayer.GetSummonedBattlePetGUID());
+ minion.SetBattlePetCompanionNameTimestamp((uint)pet.NameTimestamp);
minion.SetWildBattlePetLevel(pet.PacketInfo.Level);
}
}
diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs
index 7a83e64d4..0f256f666 100644
--- a/Source/Game/Entities/Unit/Unit.cs
+++ b/Source/Game/Entities/Unit/Unit.cs
@@ -1906,8 +1906,11 @@ namespace Game.Entities
return IsCharmed() ? GetCharmer() : GetOwner();
}
- public void SetWildBattlePetLevel(uint wildBattlePetLevel) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.WildBattlePetLevel), wildBattlePetLevel); }
+ public uint GetBattlePetCompanionNameTimestamp() { return m_unitData.BattlePetCompanionNameTimestamp; }
+ public void SetBattlePetCompanionNameTimestamp(uint timestamp) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.BattlePetCompanionNameTimestamp), timestamp); }
+
public uint GetWildBattlePetLevel() { return m_unitData.WildBattlePetLevel; }
+ public void SetWildBattlePetLevel(uint wildBattlePetLevel) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.WildBattlePetLevel), wildBattlePetLevel); }
public bool HasUnitFlag(UnitFlags flags) { return (m_unitData.Flags & (uint)flags) != 0; }
public void AddUnitFlag(UnitFlags flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Flags), (uint)flags); }
diff --git a/Source/Game/Handlers/BattlePetHandler.cs b/Source/Game/Handlers/BattlePetHandler.cs
index 45f9aa78f..23ca2e7c5 100644
--- a/Source/Game/Handlers/BattlePetHandler.cs
+++ b/Source/Game/Handlers/BattlePetHandler.cs
@@ -17,6 +17,7 @@
using Framework.Constants;
using Game.BattlePets;
+using Game.Entities;
using Game.Networking;
using Game.Networking.Packets;
@@ -54,7 +55,48 @@ namespace Game
[WorldPacketHandler(ClientOpcodes.BattlePetModifyName)]
void HandleBattlePetModifyName(BattlePetModifyName battlePetModifyName)
{
- GetBattlePetMgr().ModifyName(battlePetModifyName.PetGuid, battlePetModifyName.Name, battlePetModifyName.DeclinedName.Value);
+ GetBattlePetMgr().ModifyName(battlePetModifyName.PetGuid, battlePetModifyName.Name, battlePetModifyName.DeclinedNames.Value);
+ }
+
+ [WorldPacketHandler(ClientOpcodes.QueryBattlePetName)]
+ void HandleQueryBattlePetName(QueryBattlePetName queryBattlePetName)
+ {
+ QueryBattlePetNameResponse response = new();
+ response.BattlePetID = queryBattlePetName.BattlePetID;
+
+ Creature summonedBattlePet = ObjectAccessor.GetCreatureOrPetOrVehicle(_player, queryBattlePetName.UnitGUID);
+ if (!summonedBattlePet || !summonedBattlePet.IsSummon())
+ {
+ SendPacket(response);
+ return;
+ }
+
+ response.CreatureID = summonedBattlePet.GetEntry();
+ response.Timestamp = summonedBattlePet.GetBattlePetCompanionNameTimestamp();
+
+ Unit petOwner = summonedBattlePet.ToTempSummon().GetSummoner();
+ if (!petOwner.IsPlayer())
+ {
+ SendPacket(response);
+ return;
+ }
+
+ BattlePetMgr.BattlePet battlePet = petOwner.ToPlayer().GetSession().GetBattlePetMgr().GetPet(queryBattlePetName.BattlePetID);
+ if (battlePet == null)
+ {
+ SendPacket(response);
+ return;
+ }
+
+ response.Allow = true;
+ response.Name = battlePet.PacketInfo.Name;
+ if (battlePet.DeclinedName != null)
+ {
+ response.HasDeclined = true;
+ response.DeclinedNames = battlePet.DeclinedName;
+ }
+
+ SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.BattlePetDeletePet)]
@@ -97,7 +139,7 @@ namespace Game
[WorldPacketHandler(ClientOpcodes.BattlePetSummon, Processing = PacketProcessing.Inplace)]
void HandleBattlePetSummon(BattlePetSummon battlePetSummon)
{
- if (_player.m_activePlayerData.SummonedBattlePetGUID != battlePetSummon.PetGuid)
+ if (_player.GetSummonedBattlePetGUID() != battlePetSummon.PetGuid)
GetBattlePetMgr().SummonPet(battlePetSummon.PetGuid);
else
GetBattlePetMgr().DismissPet();
diff --git a/Source/Game/Networking/Packets/BattlePetPackets.cs b/Source/Game/Networking/Packets/BattlePetPackets.cs
index 432351971..e9bf1f067 100644
--- a/Source/Game/Networking/Packets/BattlePetPackets.cs
+++ b/Source/Game/Networking/Packets/BattlePetPackets.cs
@@ -139,7 +139,7 @@ namespace Game.Networking.Packets
if (_worldPacket.HasBit())
{
- DeclinedName.Set(new DeclinedName());
+ DeclinedNames.Set(new DeclinedName());
byte[] declinedNameLengths = new byte[SharedConst.MaxDeclinedNameCases];
@@ -147,7 +147,7 @@ namespace Game.Networking.Packets
declinedNameLengths[i] = _worldPacket.ReadBits(7);
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
- DeclinedName.Value.name[i] = _worldPacket.ReadString(declinedNameLengths[i]);
+ DeclinedNames.Value.name[i] = _worldPacket.ReadString(declinedNameLengths[i]);
}
Name = _worldPacket.ReadString(nameLength);
@@ -155,9 +155,62 @@ namespace Game.Networking.Packets
public ObjectGuid PetGuid;
public string Name;
- public Optional DeclinedName;
+ public Optional DeclinedNames;
}
+ class QueryBattlePetName : ClientPacket
+ {
+ public QueryBattlePetName(WorldPacket packet) : base(packet) { }
+
+ public override void Read()
+ {
+ BattlePetID = _worldPacket.ReadPackedGuid();
+ UnitGUID = _worldPacket.ReadPackedGuid();
+ }
+
+ public ObjectGuid BattlePetID;
+ public ObjectGuid UnitGUID;
+ }
+
+ class QueryBattlePetNameResponse : ServerPacket
+ {
+ public QueryBattlePetNameResponse() : base(ServerOpcodes.QueryBattlePetNameResponse, ConnectionType.Instance) { }
+
+ public override void Write()
+ {
+ _worldPacket.WritePackedGuid(BattlePetID);
+ _worldPacket.WriteUInt32(CreatureID);
+ _worldPacket.WriteInt64(Timestamp);
+
+ _worldPacket.WriteBit(Allow);
+
+ if (Allow)
+ {
+ _worldPacket.WriteBits(Name.GetByteCount(), 8);
+ _worldPacket.WriteBit(HasDeclined);
+
+ for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
+ _worldPacket.WriteBits(DeclinedNames.name[i].GetByteCount(), 7);
+
+ for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
+ _worldPacket.WriteString(DeclinedNames.name[i]);
+
+ _worldPacket.WriteString(Name);
+ }
+
+ _worldPacket.FlushBits();
+ }
+
+ public ObjectGuid BattlePetID;
+ public uint CreatureID;
+ public long Timestamp;
+ public bool Allow;
+
+ public bool HasDeclined;
+ public DeclinedName DeclinedNames;
+ public string Name;
+ }
+
class BattlePetDeletePet : ClientPacket
{
public BattlePetDeletePet(WorldPacket packet) : base(packet) { }
diff --git a/sql/updates/auth/master/2021_11_20_00_auth.sql b/sql/updates/auth/master/2021_11_20_00_auth.sql
new file mode 100644
index 000000000..da75c1e44
--- /dev/null
+++ b/sql/updates/auth/master/2021_11_20_00_auth.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `battle_pets` ADD `nameTimestamp` bigint(20) NOT NULL DEFAULT '0' AFTER `name`;
+
+UPDATE `battle_pets` SET `nameTimestamp`=UNIX_TIMESTAMP() WHERE LENGTH(`name`) > 0;