From eb198f8239b57bc7b93ff3e5a1c548b4359bf73c Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 11 Apr 2009 06:54:39 +0400 Subject: [PATCH] [7645] Fixed problems wit temporary unsummoned pets and cleanup code. * Save temporary unsummoned pet to current slot (instead non_in_slot mode) and prevent save as current pet summoned while temporay unsummon (arena) * Prevent overwrite temporary summoned pet data * At player loading set temporary unsummoned pet data instead pet loading if pet expected to be temporary unsummoned in current player state (loading in taxi flight/etc) * Restore proper pet at arena leave and unsummon in arena summoned. --- src/game/BattleGround.cpp | 26 +++----------- src/game/CharacterHandler.cpp | 5 ++- src/game/MovementHandler.cpp | 9 +---- src/game/NPCHandler.cpp | 5 +-- src/game/Pet.cpp | 68 ++++++++++++++++++++++++----------- src/game/Player.cpp | 67 ++++++++++++++++++++-------------- src/game/Player.h | 5 +-- src/game/Unit.cpp | 26 ++------------ src/shared/revision_nr.h | 2 +- 9 files changed, 105 insertions(+), 108 deletions(-) diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 5cd47764b..f38d8ac09 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -943,15 +943,9 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) - // summon old pet if there was one and there isn't a current pet - if (!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber()) - { - Pet* NewPet = new Pet; - if (!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true)) - delete NewPet; - - (plr)->SetTemporaryUnsummonedPetNumber(0); - } + // unsummon current and summon old pet if there was one and there isn't a current pet + plr->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT); + plr->ResummonPetTemporaryUnSummonedIfAny(); if (isRated() && GetStatus() == STATUS_IN_PROGRESS) { @@ -1105,19 +1099,7 @@ void BattleGround::AddPlayer(Player *plr) } plr->DestroyConjuredItems(true); - - Pet* pet = plr->GetPet(); - if (pet) - { - if (pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET) - { - (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); - (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - } - (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); - } - else - (plr)->SetTemporaryUnsummonedPetNumber(0); + plr->UnsummonPetTemporaryIfAny(); if(GetStatus() == STATUS_WAIT_JOIN) // not started yet { diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 37a4c863a..79cb46ee9 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -798,9 +798,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) SendDoFlight( MountId, path, startNode ); } - // Load pet if any and player is alive and not in taxi flight - if(pCurrChar->isAlive() && pCurrChar->m_taxi.GetTaxiSource()==0) - pCurrChar->LoadPet(); + // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) + pCurrChar->LoadPet(); // Set FFA PvP for non GM in non-rest mode if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) ) diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index ade662fa7..6cb6d521d 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -155,14 +155,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->CastSpell(GetPlayer(), 2479, true); // resummon pet - if(GetPlayer()->m_temporaryUnsummonedPetNumber) - { - Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB(GetPlayer(), 0, GetPlayer()->m_temporaryUnsummonedPetNumber, true)) - delete NewPet; - - GetPlayer()->m_temporaryUnsummonedPetNumber = 0; - } + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); GetPlayer()->SetDontMove(false); } diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index 7f69a769a..18b27b562 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -601,12 +601,13 @@ void WorldSession::HandleStablePet( WorldPacket & recv_data ) // slots ordered in query, and if not equal then free if(slot!=free_slot) break; - + // this slot not free, skip ++free_slot; }while( result->NextRow() ); + + delete result; } - delete result; if( free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) { diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 8e4591388..03b6c1fce 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -90,17 +90,17 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool QueryResult *result; - if(petnumber) + if (petnumber) // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND id = '%u'", ownerid, petnumber); - else if(current) + else if (current) // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND slot = '%u'", ownerid, PET_SAVE_AS_CURRENT ); - else if(petentry) + else if (petentry) // known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets) // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, talentpoints, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " @@ -120,7 +120,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool // update for case of current pet "slot = 0" petentry = fields[1].GetUInt32(); - if(!petentry) + if (!petentry) { delete result; return false; @@ -132,16 +132,24 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool bool is_temporary_summoned = spellInfo && GetSpellDuration(spellInfo) > 0; // check temporary summoned pets like mage water elemental - if(current && is_temporary_summoned) + if (current && is_temporary_summoned) { delete result; return false; } + uint32 pet_number = fields[0].GetUInt32(); + + if (current && owner->IsPetNeedBeTemporaryUnsummoned()) + { + owner->SetTemporaryUnsummonedPetNumber(pet_number); + delete result; + return false; + } + Map *map = owner->GetMap(); uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_PET); - uint32 pet_number = fields[0].GetUInt32(); - if(!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number)) + if (!Create(guid, map, owner->GetPhaseMask(), petentry, pet_number)) { delete result; return false; @@ -152,7 +160,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool Relocate(px, py, pz, owner->GetOrientation()); - if(!IsPositionValid()) + if (!IsPositionValid()) { sLog.outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", GetGUIDLow(), GetEntry(), GetPositionX(), GetPositionY()); @@ -165,7 +173,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); CreatureInfo const *cinfo = GetCreatureInfo(); - if(cinfo->type == CREATURE_TYPE_CRITTER) + if (cinfo->type == CREATURE_TYPE_CRITTER) { AIM_Initialize(); map->Add((Creature*)this); @@ -173,7 +181,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool return true; } - if(getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK)) + if (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK)) m_charmInfo->SetPetNumber(pet_number, true); else m_charmInfo->SetPetNumber(pet_number, false); @@ -185,7 +193,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool SetUInt32Value(UNIT_NPC_FLAGS, 0); SetName(fields[9].GetString()); - switch(getPetType()) + switch (getPetType()) { case SUMMON_PET: petlevel=owner->getLevel(); @@ -224,7 +232,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool // 0=current // 1..MAX_PET_STABLES in stable slot // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning)) - if(fields[8].GetUInt32() != 0) + if (fields[8].GetUInt32() != 0) { CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u' AND id <> '%u'", @@ -234,12 +242,12 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool CharacterDatabase.CommitTransaction(); } - if(!is_temporary_summoned) + if (!is_temporary_summoned) { // permanent controlled pets store state in DB Tokens tokens = StrSplit(fields[14].GetString(), " "); - if(tokens.size() != 20) + if (tokens.size() != 20) { delete result; return false; @@ -282,7 +290,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool _LoadAuras(timediff); //init AB - if(is_temporary_summoned) + if (is_temporary_summoned) { // Temporary summoned pets always have initial spell list at load InitPetCreateSpells(); @@ -293,7 +301,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool CastPetAuras(current); } - if(getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current + if (getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current { SetHealth(GetMaxHealth()); SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); @@ -314,14 +322,14 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool owner->SetPet(this); // in DB stored only full controlled creature sLog.outDebug("New Pet has guid %u", GetGUIDLow()); - if(owner->GetTypeId() == TYPEID_PLAYER) + if (owner->GetTypeId() == TYPEID_PLAYER) { ((Player*)owner)->PetSpellInitialize(); if(((Player*)owner)->GetGroup()) ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_PET); } - if(owner->GetTypeId() == TYPEID_PLAYER && getPetType() == HUNTER_PET) + if (owner->GetTypeId() == TYPEID_PLAYER && getPetType() == HUNTER_PET) { result = CharacterDatabase.PQuery("SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", owner->GetGUIDLow(), GetCharmInfo()->GetPetNumber()); @@ -345,13 +353,33 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool void Pet::SavePetToDB(PetSaveMode mode) { - if(!GetEntry()) + if (!GetEntry()) return; // save only fully controlled creature - if(!isControlled()) + if (!isControlled() && !isTemporarySummoned()) return; + // not save not player pets + if(!IS_PLAYER_GUID(GetOwnerGUID())) + return; + + Player* pOwner = (Player*)GetOwner(); + if (!pOwner) + return; + + // not save pet as current if another pet temporary unsummoned + if (mode == PET_SAVE_AS_CURRENT && pOwner->GetTemporaryUnsummonedPetNumber() && + pOwner->GetTemporaryUnsummonedPetNumber() != m_charmInfo->GetPetNumber()) + { + // pet will lost anyway at restore temporary unsummoned + if(getPetType()==HUNTER_PET) + return; + + // for warlock case + mode = PET_SAVE_NOT_IN_SLOT; + } + uint32 curhealth = GetHealth(); uint32 curmana = GetPower(POWER_MANA); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index c26f9a5fa..7d77c282b 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -1628,16 +1628,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati //SendMessageToSet(&data, true); if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { - //same map, only remove pet if out of range - if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) - { - if(pet->isControlled() && !pet->isTemporarySummoned() ) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } + //same map, only remove pet if out of range for new position + if(pet && pet->GetDistance(x,y,z) >= OWNER_MAX_DISTANCE) + UnsummonPetTemporaryIfAny(); } if(!(options & TELE_TO_NOT_LEAVE_COMBAT)) @@ -1646,14 +1639,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { // resummon pet - if(pet && m_temporaryUnsummonedPetNumber) - { - Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) - delete NewPet; - - m_temporaryUnsummonedPetNumber = 0; - } + if (pet) + ResummonPetTemporaryUnSummonedIfAny(); } uint32 newzone, newarea; @@ -1712,15 +1699,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // remove pet on map change if (pet) - { - //leaving map -> delete pet right away (doing this later will cause problems) - if(pet->isControlled() && !pet->isTemporarySummoned()) - m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); - else - m_temporaryUnsummonedPetNumber = 0; - - RemovePet(pet, PET_SAVE_NOT_IN_SLOT); - } + UnsummonPetTemporaryIfAny(); // remove all dyn objects RemoveAllDynObjects(); @@ -19807,3 +19786,37 @@ void Player::UpdateFallInformationIfNeed( MovementInfo const& minfo,uint16 opcod if (m_lastFallTime >= minfo.fallTime || m_lastFallZ <=minfo.z || opcode == MSG_MOVE_FALL_LAND) SetFallInformation(minfo.fallTime, minfo.z); } + +void Player::UnsummonPetTemporaryIfAny() +{ + Pet* pet = GetPet(); + if(!pet) + return; + + if(!m_temporaryUnsummonedPetNumber && pet->isControlled() && !pet->isTemporarySummoned() ) + { + m_temporaryUnsummonedPetNumber = pet->GetCharmInfo()->GetPetNumber(); + m_oldpetspell = pet->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + RemovePet(pet, PET_SAVE_AS_CURRENT); +} + +void Player::ResummonPetTemporaryUnSummonedIfAny() +{ + if(!m_temporaryUnsummonedPetNumber) + return; + + // not resummon in not appropriate state + if(IsPetNeedBeTemporaryUnsummoned()) + return; + + if(GetPetGUID()) + return; + + Pet* NewPet = new Pet; + if(!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true)) + delete NewPet; + + m_temporaryUnsummonedPetNumber = 0; +} diff --git a/src/game/Player.h b/src/game/Player.h index cc71fa579..abc3f6ce8 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1974,8 +1974,9 @@ class MANGOS_DLL_SPEC Player : public Unit // Temporarily removed pet cache uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } - uint32 GetOldPetSpell() const { return m_oldpetspell; } - void SetOldPetSpell(uint32 petspell) { m_oldpetspell = petspell; } + void UnsummonPetTemporaryIfAny(); + void ResummonPetTemporaryUnSummonedIfAny(); + bool IsPetNeedBeTemporaryUnsummoned() const { return !IsInWorld() || !isAlive() || IsMounted() /*+in flight*/; } void SendCinematicStart(uint32 CinematicSequenceId); void SendMovieStart(uint32 MovieId); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 7d2264b94..66b18d0c9 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -8549,21 +8549,7 @@ void Unit::Mount(uint32 mount) // unsummon pet if(GetTypeId() == TYPEID_PLAYER) - { - Pet* pet = GetPet(); - if(pet) - { - if(pet->isControlled()) - { - ((Player*)this)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber()); - ((Player*)this)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL)); - } - - ((Player*)this)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT); - } - else - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } + ((Player*)this)->UnsummonPetTemporaryIfAny(); } void Unit::Unmount() @@ -8579,14 +8565,8 @@ void Unit::Unmount() // only resummon old pet if the player is already added to a map // this prevents adding a pet to a not created map which would otherwise cause a crash // (it could probably happen when logging in after a previous crash) - if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive()) - { - Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB((Player*)this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) - delete NewPet; - - ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); - } + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->ResummonPetTemporaryUnSummonedIfAny(); } void Unit::SetInCombatWith(Unit* enemy) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 0792696ee..67e98d93a 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7644" + #define REVISION_NR "7645" #endif // __REVISION_NR_H__