diff options
| author | Shauren <shauren.trinity@gmail.com> | 2022-10-21 22:11:00 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2022-10-21 22:11:00 +0200 |
| commit | 879c0cccfcb9224f9e15cbed926c57a4e010a070 (patch) | |
| tree | bb01bada60e1c943b6981919945b1a91b4da1c11 /src/server/game/Entities/GameObject | |
| parent | 43ac108a527fc593b4d5fa1fb06ff98e843d0b84 (diff) | |
Core/GameObjects: Implemented per player gameobject state and visibility for looted non-consumable chests
Diffstat (limited to 'src/server/game/Entities/GameObject')
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 100 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 16 |
2 files changed, 113 insertions, 3 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 4dffcf2652e..1e50e56f2a3 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -901,6 +901,44 @@ void GameObject::Update(uint32 diff) if (m_goTypeImpl) m_goTypeImpl->Update(diff); + if (m_perPlayerState) + { + for (auto itr = m_perPlayerState->begin(); itr != m_perPlayerState->end(); ) + { + if (itr->second.ValidUntil > GameTime::GetSystemTime()) + { + ++itr; + continue; + } + + Player* seer = ObjectAccessor::GetPlayer(*this, itr->first); + bool needsStateUpdate = itr->second.State != GetGoState(); + bool despawned = itr->second.Despawned; + + itr = m_perPlayerState->erase(itr); + + if (seer) + { + if (despawned) + { + seer->UpdateVisibilityOf(this); + } + else if (needsStateUpdate) + { + UF::ObjectData::Base objMask; + UF::GameObjectData::Base goMask; + goMask.MarkChanged(&UF::GameObjectData::State); + + UpdateData udata(GetMapId()); + BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), seer); + WorldPacket packet; + udata.BuildPacket(&packet); + seer->SendDirectMessage(&packet); + } + } + } + } + switch (m_lootState) { case GO_NOT_READY: @@ -1795,15 +1833,20 @@ bool GameObject::IsAlwaysVisibleFor(WorldObject const* seer) const return false; } -bool GameObject::IsInvisibleDueToDespawn() const +bool GameObject::IsInvisibleDueToDespawn(WorldObject const* seer) const { - if (WorldObject::IsInvisibleDueToDespawn()) + if (WorldObject::IsInvisibleDueToDespawn(seer)) return true; // Despawned if (!isSpawned()) return true; + if (m_perPlayerState) + if (PerPlayerState const* state = Trinity::Containers::MapGetValuePtr(*m_perPlayerState, seer->GetGUID())) + if (state->Despawned) + return true; + return false; } @@ -3189,6 +3232,29 @@ bool GameObject::IsFullyLooted() const return true; } +void GameObject::OnLootRelease(Player* looter) +{ + switch (GetGoType()) + { + case GAMEOBJECT_TYPE_CHEST: + { + GameObjectTemplate const* goInfo = GetGOInfo(); + if (!goInfo->chest.consumable && goInfo->chest.chestPersonalLoot) + { + PerPlayerState& perPlayerState = GetOrCreatePerPlayerStates()[looter->GetGUID()]; + perPlayerState.ValidUntil = GameTime::GetSystemTime() + (goInfo->chest.chestRestockTime + ? Seconds(goInfo->chest.chestRestockTime) + : Seconds(m_respawnDelayTime)); // not hiding this object permanently to prevent infinite growth of m_perPlayerState + // while also maintaining some sort of cheater protection (not getting rid of entries on logout) + perPlayerState.Despawned = true; + + looter->UpdateVisibilityOf(this); + } + break; + } + } +} + void GameObject::SetGoState(GOState state) { GOState oldState = GetGoState(); @@ -3213,6 +3279,28 @@ void GameObject::SetGoState(GOState state) } } +GOState GameObject::GetGoStateFor(ObjectGuid const& viewer) const +{ + if (m_perPlayerState) + if (PerPlayerState const* state = Trinity::Containers::MapGetValuePtr(*m_perPlayerState, viewer)) + if (state->State) + return *state->State; + + return GetGoState(); +} + +void GameObject::SetGoStateFor(GOState state, Player const* viewer) +{ + PerPlayerState& perPlayerState = GetOrCreatePerPlayerStates()[viewer->GetGUID()]; + perPlayerState.ValidUntil = GameTime::GetSystemTime() + Seconds(m_respawnDelayTime); + perPlayerState.State = state; + + WorldPackets::GameObject::GameObjectSetStateLocal setStateLocal; + setStateLocal.ObjectGUID = GetGUID(); + setStateLocal.State = state; + viewer->SendDirectMessage(setStateLocal.Write()); +} + void GameObject::SetDisplayId(uint32 displayid) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::DisplayID), displayid); @@ -3690,6 +3778,14 @@ bool GameObject::CanInteractWithCapturePoint(Player const* target) const || m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured; } +std::unordered_map<ObjectGuid, GameObject::PerPlayerState>& GameObject::GetOrCreatePerPlayerStates() +{ + if (!m_perPlayerState) + m_perPlayerState = std::make_unique<std::unordered_map<ObjectGuid, PerPlayerState>>(); + + return *m_perPlayerState; +} + class GameObjectModelOwnerImpl : public GameObjectModelOwnerBase { public: diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 7d7d0563532..6341d9ecaea 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -237,6 +237,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void SetGoType(GameobjectTypes type) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::TypeID), type); } GOState GetGoState() const { return GOState(*m_gameObjectData->State); } void SetGoState(GOState state); + GOState GetGoStateFor(ObjectGuid const& viewer) const; + void SetGoStateFor(GOState state, Player const* viewer); uint32 GetGoArtKit() const { return m_gameObjectData->ArtKit; } void SetGoArtKit(uint32 artkit); uint8 GetGoAnimProgress() const { return m_gameObjectData->PercentHealth; } @@ -261,6 +263,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; } void ResetLootMode() { m_LootMode = LOOT_MODE_DEFAULT; } bool IsFullyLooted() const; + void OnLootRelease(Player* looter); void AddToSkillupList(ObjectGuid const& PlayerGuidLow) { m_SkillupList.insert(PlayerGuidLow); } bool IsInSkillupList(ObjectGuid const& playerGuid) const @@ -301,7 +304,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> bool IsNeverVisibleFor(WorldObject const* seer) const override; bool IsAlwaysVisibleFor(WorldObject const* seer) const override; - bool IsInvisibleDueToDespawn() const override; + bool IsInvisibleDueToDespawn(WorldObject const* seer) const override; uint8 GetLevelForTarget(WorldObject const* target) const override; @@ -446,5 +449,16 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> bool m_respawnCompatibilityMode; uint16 _animKitId; uint32 _worldEffectID; + + struct PerPlayerState + { + SystemTimePoint ValidUntil = SystemTimePoint::min(); + Optional<GOState> State; + bool Despawned = false; + }; + + std::unique_ptr<std::unordered_map<ObjectGuid, PerPlayerState>> m_perPlayerState; + + std::unordered_map<ObjectGuid, PerPlayerState>& GetOrCreatePerPlayerStates(); }; #endif |
