feat(Core/Pets): Management refactoring (#9712)

* feat(Core/Pets): rework managment

* 1

* 2

* 3

* 4

* 5

* cs pet

* check before ressurect

* pet DECLINED_NAMES

* display

- https://github.com/azerothcore/azerothcore-wotlk/issues/9297

* ArenaSpectator

* 1
This commit is contained in:
Kargatum
2021-12-31 04:45:13 +07:00
committed by GitHub
parent 24ab99919a
commit e12494d993
24 changed files with 1173 additions and 1208 deletions

View File

@@ -488,74 +488,61 @@ void WorldSession::HandleListStabledPetsOpcode(WorldPacket& recvData)
void WorldSession::SendStablePet(ObjectGuid guid)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS_DETAIL);
stmt->setUInt32(0, _player->GetGUID().GetCounter());
stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT);
stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT);
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::SendStablePetCallback, this, guid, std::placeholders::_1)));
}
void WorldSession::SendStablePetCallback(ObjectGuid guid, PreparedQueryResult result)
{
if (!GetPlayer())
return;
LOG_DEBUG("network", "WORLD: Recv MSG_LIST_STABLED_PETS Send.");
WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size
data << guid;
size_t wpos = data.wpos();
data << uint8(0); // place holder for slot show number
data << uint8(GetPlayer()->m_stableSlots);
Pet* pet = _player->GetPet();
PetStable* petStable = GetPlayer()->GetPetStable();
if (!petStable)
{
data << uint8(0); // stable slots
SendPacket(&data);
return;
}
data << uint8(petStable->MaxStabledPets);
uint8 num = 0; // counter for place holder
// not let move dead pet in slot
if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET)
if (petStable->CurrentPet)
{
data << uint32(pet->GetCharmInfo()->GetPetNumber());
data << uint32(pet->GetEntry());
data << uint32(pet->getLevel());
data << pet->GetName(); // petname
data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show)
PetStable::PetInfo const& pet = *petStable->CurrentPet;
data << uint32(pet.PetNumber);
data << uint32(pet.CreatureId);
data << uint32(pet.Level);
data << pet.Name; // petname
data << uint8(1); // flags: 1 active, 2 inactive
++num;
}
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
else
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_SYNS);
stmt->setUInt32(0, _player->GetGUID().GetCounter());
stmt->setUInt8(1, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
if (PreparedQueryResult _result = CharacterDatabase.Query(stmt))
if (PetStable::PetInfo const* pet = petStable->GetUnslottedHunterPet())
{
Field* fields = _result->Fetch();
data << uint32(fields[0].GetUInt32()); // id
data << uint32(fields[1].GetUInt32()); // entry
data << uint32(fields[4].GetUInt16()); // level
data << fields[8].GetString(); // petname
data << uint8(1);
data << uint32(pet->PetNumber);
data << uint32(pet->CreatureId);
data << uint32(pet->Level);
data << pet->Name; // petname
data << uint8(1); // flags: 1 active, 2 inactive
++num;
}
}
if (result)
for (Optional<PetStable::PetInfo> const& stabledSlot : petStable->StabledPets)
{
do
if (stabledSlot)
{
Field* fields = result->Fetch();
data << uint32(fields[1].GetUInt32()); // petnumber
data << uint32(fields[2].GetUInt32()); // creature entry
data << uint32(fields[3].GetUInt16()); // level
data << fields[4].GetString(); // name
data << uint8(2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show)
PetStable::PetInfo const& pet = *stabledSlot;
data << uint32(pet.PetNumber);
data << uint32(pet.CreatureId);
data << uint32(pet.Level);
data << pet.Name; // petname
data << uint8(2); // flags: 1 active, 2 inactive
++num;
} while (result->NextRow());
}
}
data.put<uint8>(wpos, num); // set real data to placeholder
@@ -592,81 +579,49 @@ void WorldSession::HandleStablePet(WorldPacket& recvData)
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
PetStable* petStable = GetPlayer()->GetPetStable();
if (!petStable)
return;
Pet* pet = _player->GetPet();
// can't place in stable dead pet
if (pet)
if ((pet && (!pet->IsAlive() || pet->getPetType() != HUNTER_PET))
|| (!pet && (petStable->UnslottedPets.size() != 1 || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)))
{
if (!pet->IsAlive() || pet->getPetType() != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
}
else
{
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
if (loadResult != SPELL_CAST_OK)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS);
stmt->setUInt32(0, _player->GetGUID().GetCounter());
stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT);
stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT);
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStablePetCallback, this, std::placeholders::_1)));
}
void WorldSession::HandleStablePetCallback(PreparedQueryResult result)
{
if (!GetPlayer())
SendStableResult(STABLE_ERR_STABLE);
return;
uint8 freeSlot = 1;
if (result)
{
do
{
Field* fields = result->Fetch();
uint8 slot = fields[1].GetUInt8();
// slots ordered in query, and if not equal then free
if (slot != freeSlot)
break;
// this slot not free, skip
++freeSlot;
} while (result->NextRow());
}
WorldPacket data(SMSG_STABLE_RESULT, 1);
if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots)
for (uint32 freeSlot = 0; freeSlot < petStable->MaxStabledPets; ++freeSlot)
{
if (_player->GetPetGUID())
if (!petStable->StabledPets[freeSlot])
{
_player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot));
if (pet)
{
// stable summoned pet
_player->RemovePet(pet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
std::swap(petStable->StabledPets[freeSlot], petStable->CurrentPet);
SendStableResult(STABLE_SUCCESS_STABLE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + freeSlot));
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
CharacterDatabase.Execute(stmt);
// stable unsummoned pet
petStable->StabledPets[freeSlot] = std::move(petStable->UnslottedPets.back());
petStable->UnslottedPets.pop_back();
SendStableResult(STABLE_SUCCESS_STABLE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
stmt->setUInt8(0, freeSlot);
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
CharacterDatabase.Execute(stmt);
_player->SetTemporaryUnsummonedPetNumber(0);
SendStableResult(STABLE_SUCCESS_STABLE);
return;
}
else
SendStableResult(STABLE_ERR_STABLE);
// not free stable slot
SendStableResult(STABLE_ERR_STABLE);
}
void WorldSession::HandleUnstablePet(WorldPacket& recvData)
@@ -687,37 +642,25 @@ void WorldSession::HandleUnstablePet(WorldPacket& recvData)
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_ENTRY);
stmt->setUInt32(0, _player->GetGUID().GetCounter());
stmt->setUInt32(1, petnumber);
stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT);
stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT);
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUnstablePetCallback, this, petnumber, std::placeholders::_1)));
}
void WorldSession::HandleUnstablePetCallback(uint32 petId, PreparedQueryResult result)
{
if (!GetPlayer())
return;
uint32 petEntry = 0;
uint32 slot = 0;
if (result)
{
Field* fields = result->Fetch();
petEntry = fields[0].GetUInt32();
slot = fields[1].GetUInt32();
}
if (!petEntry)
PetStable* petStable = GetPlayer()->GetPetStable();
if (!petStable)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry);
auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petnumber](Optional<PetStable::PetInfo> const& pet)
{
return pet && pet->PetNumber == petnumber;
});
if (stabledPet == petStable->StabledPets.end())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
@@ -725,45 +668,74 @@ void WorldSession::HandleUnstablePetCallback(uint32 petId, PreparedQueryResult r
SendStableResult(STABLE_ERR_EXOTIC);
else
SendStableResult(STABLE_ERR_STABLE);
return;
}
Pet* pet = _player->GetPet();
if (pet && pet->IsAlive())
Pet* oldPet = _player->GetPet();
if (oldPet)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// delete dead pet
if (pet)
{
_player->RemovePet(pet, PET_SAVE_AS_DELETED);
}
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
{
// try to find if pet is actually temporary unsummoned and alive
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
if (loadResult != SPELL_CAST_OK)
// try performing a swap, client sends this packet instead of swap when starting from stabled slot
if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
stmt->setUInt8(0, slot);
_player->RemovePet(oldPet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
}
else if (petStable->UnslottedPets.size() == 1)
{
if (petStable->CurrentPet || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
CharacterDatabase.Execute(stmt);
_player->SetTemporaryUnsummonedPetNumber(0);
// move unsummoned pet into CurrentPet slot so that it gets moved into stable slot later
petStable->CurrentPet = std::move(petStable->UnslottedPets.back());
petStable->UnslottedPets.pop_back();
}
if (!Pet::LoadPetFromDB(_player, PET_LOAD_HANDLE_UNSTABLE_CALLBACK, petEntry, petId))
else if (petStable->CurrentPet || !petStable->UnslottedPets.empty())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
Pet* newPet = new Pet(_player, HUNTER_PET);
if (!newPet->LoadPetFromDB(_player, 0, petnumber, false))
{
delete newPet;
petStable->UnslottedPets.push_back(std::move(*petStable->CurrentPet));
petStable->CurrentPet.reset();
// update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PET_SAVE_NOT_IN_SLOT);
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt32(2, petnumber);
CharacterDatabase.Execute(stmt);
SendStableResult(STABLE_ERR_STABLE);
}
else
{
// update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt32(2, petnumber);
CharacterDatabase.Execute(stmt);
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
}
void WorldSession::HandleBuyStableSlot(WorldPacket& recvData)
@@ -783,12 +755,13 @@ void WorldSession::HandleBuyStableSlot(WorldPacket& recvData)
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if (GetPlayer()->m_stableSlots < MAX_PET_STABLES)
PetStable& petStable = GetPlayer()->GetOrInitPetStable();
if (petStable.MaxStabledPets < MAX_PET_STABLES)
{
StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots + 1);
StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(petStable.MaxStabledPets + 1);
if (_player->HasEnoughMoney(SlotPrice->Price))
{
++GetPlayer()->m_stableSlots;
++petStable.MaxStabledPets;
_player->ModifyMoney(-int32(SlotPrice->Price));
SendStableResult(STABLE_SUCCESS_BUY_SLOT);
}
@@ -822,58 +795,26 @@ void WorldSession::HandleStableSwapPet(WorldPacket& recvData)
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
Pet* pet = _player->GetPet();
if (pet)
PetStable* petStable = GetPlayer()->GetPetStable();
if (!petStable)
{
if (pet->getPetType() != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
}
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
{
// try to find if pet is actually temporary unsummoned and alive
SpellCastResult loadResult = Pet::TryLoadFromDB(_player, _player->GetTemporaryUnsummonedPetNumber() != 0, HUNTER_PET);
if (loadResult != SPELL_CAST_OK)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
SendStableResult(STABLE_ERR_STABLE);
return;
}
// Find swapped pet slot in stable
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOT_BY_ID);
auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petId](Optional<PetStable::PetInfo> const& pet)
{
return pet && pet->PetNumber == petId;
});
stmt->setUInt32(0, _player->GetGUID().GetCounter());
stmt->setUInt32(1, petId);
_queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStableSwapPetCallback, this, petId, std::placeholders::_1)));
}
void WorldSession::HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult result)
{
if (!GetPlayer())
return;
if (!result)
if (stabledPet == petStable->StabledPets.end())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
Field* fields = result->Fetch();
uint32 slot = fields[0].GetUInt8();
uint32 petEntry = fields[1].GetUInt32();
if (!petEntry)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry);
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((*stabledPet)->CreatureId);
if (!creatureInfo || !creatureInfo->IsTameable(_player->CanTameExoticPets()))
{
// if problem in exotic pet
@@ -884,29 +825,69 @@ void WorldSession::HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult
return;
}
Pet* pet = _player->GetPet();
// move alive pet to slot or delete dead pet
if (pet)
_player->RemovePet(pet, pet->IsAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED);
else if (_player->IsPetDismissed() || _player->GetTemporaryUnsummonedPetNumber())
Pet* oldPet = _player->GetPet();
if (oldPet)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT);
stmt->setUInt8(0, slot);
if (!oldPet->IsAlive() || !oldPet->IsHunterPet())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
_player->RemovePet(oldPet, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
}
else if (petStable->UnslottedPets.size() == 1)
{
if (petStable->CurrentPet || !petStable->UnslottedPets[0].Health || petStable->UnslottedPets[0].Type != HUNTER_PET)
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + std::distance(petStable->StabledPets.begin(), stabledPet)));
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt8(2, uint8(_player->GetTemporaryUnsummonedPetNumber() ? PET_SAVE_AS_CURRENT : PET_SAVE_NOT_IN_SLOT));
stmt->setUInt32(2, petStable->UnslottedPets[0].PetNumber);
CharacterDatabase.Execute(stmt);
_player->SetTemporaryUnsummonedPetNumber(0);
// move unsummoned pet into CurrentPet slot so that it gets moved into stable slot later
petStable->CurrentPet = std::move(petStable->UnslottedPets.back());
petStable->UnslottedPets.pop_back();
}
else if (petStable->CurrentPet || !petStable->UnslottedPets.empty())
{
SendStableResult(STABLE_ERR_STABLE);
return;
}
// summon unstabled pet
if (!Pet::LoadPetFromDB(_player, PET_LOAD_HANDLE_UNSTABLE_CALLBACK, petEntry, petId))
Pet* newPet = new Pet(_player, HUNTER_PET);
if (!newPet->LoadPetFromDB(_player, 0, petId, false))
{
delete newPet;
SendStableResult(STABLE_ERR_STABLE);
petStable->UnslottedPets.push_back(std::move(*petStable->CurrentPet));
petStable->CurrentPet.reset();
// update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PET_SAVE_NOT_IN_SLOT);
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt32(2, petId);
CharacterDatabase.Execute(stmt);
}
else
{
// update current pet slot in db immediately to maintain slot consistency, dismissed pet was already saved
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
stmt->setUInt32(1, _player->GetGUID().GetCounter());
stmt->setUInt32(2, petId);
CharacterDatabase.Execute(stmt);
SendStableResult(STABLE_SUCCESS_UNSTABLE);
}
}
void WorldSession::HandleRepairItemOpcode(WorldPacket& recvData)