diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-09-10 11:54:09 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-09-10 11:54:09 +0200 |
commit | a667d723bf18ffba9b7b25c4fff1223d23e55524 (patch) | |
tree | 3c30f5668407de815cdb6448c3932dfab98b89cf /src | |
parent | edb103eadbee04aa2cd6746409e0fe297ba15958 (diff) |
Core/Pets: Improved pet despawn behavior when mounting
* Pets will now only be despawned when starting to fly
* Fixed crash when summoning a pet that is different than the one that was despawned by flying
Closes #29303
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Pet/Pet.cpp | 16 | ||||
-rw-r--r-- | src/server/game/Entities/Pet/Pet.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 45 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 32 | ||||
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/PetHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Server/Packets/PetPackets.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Server/Packets/PetPackets.h | 13 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 |
11 files changed, 96 insertions, 39 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a83dfea2a48..39b83cf62a1 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3068,9 +3068,13 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const if (IsFriendlyTo(target) || target->IsFriendlyTo(this)) return false; - Player const* playerAffectingAttacker = unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) ? GetAffectingPlayer() : go ? GetAffectingPlayer() : nullptr; + Player const* playerAffectingAttacker = (unit && unit->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) || go ? GetAffectingPlayer() : nullptr; Player const* playerAffectingTarget = unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) ? unitTarget->GetAffectingPlayer() : nullptr; + // Pets of mounted players are immune to NPCs + if (!playerAffectingAttacker && unitTarget && unitTarget->IsPet() && playerAffectingTarget && playerAffectingTarget->IsMounted()) + return false; + // Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar) if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget)) { diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index e4e367c1d94..dd66132f216 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -244,6 +244,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c return false; } + owner->SetTemporaryUnsummonedPetNumber(0); + Map* map = owner->GetMap(); ObjectGuid::LowType guid = map->GenerateLowGuid<HighGuid::Pet>(); @@ -366,9 +368,6 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c uint32 newPetIndex = std::distance(petStable->ActivePets.begin(), activePetItr); - // Check that we either have no pet (unsummoned by player) or it matches temporarily unsummoned pet by server (for example on flying mount) - ASSERT(!petStable->CurrentPetIndex || petStable->CurrentPetIndex == newPetIndex); - petStable->SetCurrentActivePetIndex(newPetIndex); } @@ -456,6 +455,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c } } + if (owner->IsMounted()) + owner->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW); + // must be after SetMinion (owner guid check) LoadTemplateImmunities(); m_loading = false; @@ -525,7 +527,7 @@ void Pet::SavePetToDB(PetSaveMode mode) std::string actionBar = GenerateActionBarData(); ASSERT(owner->GetPetStable()->GetCurrentPet() && owner->GetPetStable()->GetCurrentPet()->PetNumber == m_charmInfo->GetPetNumber()); - FillPetInfo(owner->GetPetStable()->GetCurrentPet()); + FillPetInfo(owner->GetPetStable()->GetCurrentPet(), owner->GetTemporaryPetReactState()); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET); stmt->setUInt32(0, m_charmInfo->GetPetNumber()); @@ -534,7 +536,7 @@ void Pet::SavePetToDB(PetSaveMode mode) stmt->setUInt32(3, GetNativeDisplayId()); stmt->setUInt8(4, GetLevel()); stmt->setUInt32(5, m_unitData->PetExperience); - stmt->setUInt8(6, GetReactState()); + stmt->setUInt8(6, owner->GetTemporaryPetReactState().value_or(GetReactState())); stmt->setInt16(7, owner->GetPetStable()->GetCurrentActivePetIndex().value_or(PET_SAVE_NOT_IN_SLOT)); stmt->setString(8, m_name); stmt->setUInt8(9, HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED) ? 0 : 1); @@ -557,14 +559,14 @@ void Pet::SavePetToDB(PetSaveMode mode) } } -void Pet::FillPetInfo(PetStable::PetInfo* petInfo) const +void Pet::FillPetInfo(PetStable::PetInfo* petInfo, Optional<ReactStates> forcedReactState /*= {}*/) const { petInfo->PetNumber = m_charmInfo->GetPetNumber(); petInfo->CreatureId = GetEntry(); petInfo->DisplayId = GetNativeDisplayId(); petInfo->Level = GetLevel(); petInfo->Experience = m_unitData->PetExperience; - petInfo->ReactState = GetReactState(); + petInfo->ReactState = forcedReactState.value_or(GetReactState()); petInfo->Name = GetName(); petInfo->WasRenamed = !HasPetFlag(UNIT_PET_FLAG_CAN_BE_RENAMED); petInfo->Health = GetHealth(); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index a03ab823bb4..64bd4836999 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -63,7 +63,7 @@ class TC_GAME_API Pet : public Guardian bool LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current, Optional<PetSaveMode> forcedSlot = {}); bool IsLoading() const override { return m_loading;} void SavePetToDB(PetSaveMode mode); - void FillPetInfo(PetStable::PetInfo* petInfo) const; + void FillPetInfo(PetStable::PetInfo* petInfo, Optional<ReactStates> forcedReactState = {}) const; void Remove(PetSaveMode mode, bool returnreagent = false); static void DeleteFromDB(uint32 petNumber); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a52afe95a6d..ff98de25a2e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -26686,6 +26686,49 @@ void Player::UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcod SetFallInformation(minfo.jump.fallTime, minfo.pos.GetPositionZ()); } +void Player::DisablePetControlsOnMount(ReactStates reactState, CommandStates commandState) +{ + Pet* pet = GetPet(); + if (!pet) + return; + + m_temporaryPetReactState = pet->GetReactState(); + pet->SetReactState(reactState); + if (CharmInfo* charmInfo = pet->GetCharmInfo()) + charmInfo->SetCommandState(commandState); + + pet->GetMotionMaster()->MoveFollow(this, PET_FOLLOW_DIST, pet->GetFollowAngle()); + + WorldPackets::Pet::PetMode petMode; + petMode.PetGUID = pet->GetGUID(); + petMode.ReactState = reactState; + petMode.CommandState = commandState; + petMode.Flag = 0; + SendDirectMessage(petMode.Write()); +} + +void Player::EnablePetControlsOnDismount() +{ + if (Pet* pet = GetPet()) + { + WorldPackets::Pet::PetMode petMode; + petMode.PetGUID = pet->GetGUID(); + if (m_temporaryPetReactState) + { + petMode.ReactState = *m_temporaryPetReactState; + pet->SetReactState(*m_temporaryPetReactState); + } + + if (CharmInfo* charmInfo = pet->GetCharmInfo()) + petMode.CommandState = charmInfo->GetCommandState(); + + petMode.Flag = 0; + SendDirectMessage(petMode.Write()); + } + + m_temporaryPetReactState.reset(); +} + void Player::UnsummonPetTemporaryIfAny() { Pet* pet = GetPet(); @@ -26722,7 +26765,7 @@ void Player::ResummonPetTemporaryUnSummonedIfAny() bool Player::IsPetNeedBeTemporaryUnsummoned() const { - return !IsInWorld() || !IsAlive() || IsMounted() /*+in flight*/; + return !IsInWorld() || !IsAlive() || HasUnitMovementFlag(MOVEMENTFLAG_FLYING) || HasExtraUnitMovementFlag2(MOVEMENTFLAG3_ADV_FLYING); } bool Player::CanSeeSpellClickOn(Creature const* c) const diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index adf692b7507..58adcd3424f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2531,6 +2531,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> // Temporarily removed pet cache uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } + Optional<ReactStates> GetTemporaryPetReactState() const { return m_temporaryPetReactState; } + void DisablePetControlsOnMount(ReactStates reactState, CommandStates commandState); + void EnablePetControlsOnDismount(); void UnsummonPetTemporaryIfAny(); void ResummonPetTemporaryUnSummonedIfAny(); bool IsPetNeedBeTemporaryUnsummoned() const; @@ -3172,6 +3175,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> // Temporary removed pet cache uint32 m_temporaryUnsummonedPetNumber; + Optional<ReactStates> m_temporaryPetReactState; uint32 m_oldpetspell; std::unique_ptr<PlayerAchievementMgr> m_achievementMgr; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index dd1525cb783..c017eb0261c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -7766,22 +7766,8 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) } } - // unsummon pet - Pet* pet = player->GetPet(); - if (pet) - { - Battleground* bg = ToPlayer()->GetBattleground(); - // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface - if (bg && bg->isArena()) - pet->SetUnitFlag(UNIT_FLAG_STUNNED); - else - player->UnsummonPetTemporaryIfAny(); - } - - // if we have charmed npc, stun him also (everywhere) - if (Unit* charm = player->GetCharmed()) - if (charm->GetTypeId() == TYPEID_UNIT) - charm->SetUnitFlag(UNIT_FLAG_STUNNED); + // disable pet controls + player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW); player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount); } @@ -7816,18 +7802,8 @@ void Unit::Dismount() // (it could probably happen when logging in after a previous crash) if (Player* player = ToPlayer()) { - if (Pet* pPet = player->GetPet()) - { - if (pPet->HasUnitFlag(UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED)) - pPet->RemoveUnitFlag(UNIT_FLAG_STUNNED); - } - else - player->ResummonPetTemporaryUnSummonedIfAny(); - - // if we have charmed npc, remove stun also - if (Unit* charm = player->GetCharmed()) - if (charm->GetTypeId() == TYPEID_UNIT && charm->HasUnitFlag(UNIT_FLAG_STUNNED) && !charm->HasUnitState(UNIT_STATE_STUNNED)) - charm->RemoveUnitFlag(UNIT_FLAG_STUNNED); + player->EnablePetControlsOnDismount(); + player->ResummonPetTemporaryUnSummonedIfAny(); } } diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 6f9dfa69337..103daba53d3 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -401,6 +401,9 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem if (opcode == CMSG_MOVE_FALL_LAND || opcode == CMSG_MOVE_START_SWIM || opcode == CMSG_MOVE_SET_FLY) mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LandingOrFlight); // Parachutes + if (opcode == CMSG_MOVE_SET_FLY || opcode == CMSG_MOVE_SET_ADV_FLY) + _player->UnsummonPetTemporaryIfAny(); // always do the pet removal on current client activeplayer only + /* process position-change */ movementInfo.guid = mover->GetGUID(); movementInfo.time = AdjustClientMovementTime(movementInfo.time); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index d05e6c5b181..268c839f237 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -62,6 +62,9 @@ void WorldSession::HandleDismissCritter(WorldPackets::Pet::DismissCritter& packe void WorldSession::HandlePetAction(WorldPackets::Pet::PetAction& packet) { + if (_player->IsMounted()) + return; + ObjectGuid guid1 = packet.PetGUID; //pet guid ObjectGuid guid2 = packet.TargetGUID; //tag guid diff --git a/src/server/game/Server/Packets/PetPackets.cpp b/src/server/game/Server/Packets/PetPackets.cpp index ff8b278461a..089db0e4daa 100644 --- a/src/server/game/Server/Packets/PetPackets.cpp +++ b/src/server/game/Server/Packets/PetPackets.cpp @@ -195,3 +195,12 @@ WorldPacket const* WorldPackets::Pet::PetTameFailure::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Pet::PetMode::Write() +{ + _worldPacket << PetGUID; + _worldPacket << uint16(CommandState | Flag << 8); + _worldPacket << uint8(ReactState); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/PetPackets.h b/src/server/game/Server/Packets/PetPackets.h index 0d3aaaccbad..5acb43ee839 100644 --- a/src/server/game/Server/Packets/PetPackets.h +++ b/src/server/game/Server/Packets/PetPackets.h @@ -257,6 +257,19 @@ namespace WorldPackets uint8 Result = 0; }; + + class PetMode final : public ServerPacket + { + public: + PetMode() : ServerPacket(SMSG_PET_MODE, 16 + 2 + 1) { } + + WorldPacket const* Write() override; + + ObjectGuid PetGUID; + ReactStates ReactState = REACT_PASSIVE; + CommandStates CommandState = COMMAND_STAY; + uint8 Flag = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 9d017c8d871..9c3d530ed5f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1810,7 +1810,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_GUIDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_MODE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NAME_INVALID, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_NEWLY_TAMED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_SPELLS_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); |