diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 116 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 26 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 24 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 2 | ||||
-rw-r--r-- | src/server/game/Phasing/PhasingHandler.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Phasing/PhasingHandler.h | 2 |
7 files changed, 169 insertions, 16 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index e926d7d5aab..7236a02718c 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -163,6 +163,9 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId()) flags.AnimKit = true; + + if (worldObject->IsReplacingObjectFor(target)) + flags.SmoothPhasing = true; } if (Unit const* unit = ToUnit()) @@ -178,7 +181,7 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c buf << GetGUID(); buf << uint8(objectType); - BuildMovementUpdate(&buf, flags); + BuildMovementUpdate(&buf, flags, target); BuildValuesCreate(&buf, target); data->AddUpdateBlock(buf); } @@ -255,7 +258,7 @@ void Object::SendOutOfRangeForPlayer(Player* target) const target->SendDirectMessage(&packet); } -void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags) const +void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player* target) const { std::vector<uint32> const* PauseTimes = nullptr; uint32 PauseTimesCount = 0; @@ -559,15 +562,17 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags) const *data << uint32(Int1); } - //if (flags.SmoothPhasing) - //{ - // data->WriteBit(ReplaceActive); - // data->WriteBit(StopAnimKits); - // data->WriteBit(HasReplaceObject); - // data->FlushBits(); - // if (HasReplaceObject) - // *data << ObjectGuid(ReplaceObject); - //} + if (flags.SmoothPhasing) + { + ReplaceObjectInfo const* replacedObjectInfo = static_cast<WorldObject const*>(this)->GetReplacedObjectFor(target); + ASSERT(replacedObjectInfo); + + data->WriteBit(true); // ReplaceActive + data->WriteBit(replacedObjectInfo->StopAnimKits); + data->WriteBit(true); + data->FlushBits(); + *data << ObjectGuid(replacedObjectInfo->ReplaceObject); + } if (flags.SceneObject) { @@ -922,6 +927,8 @@ void WorldObject::RemoveFromWorld() if (!IsInWorld()) return; + RestoreReplacedObject(); + UpdateObjectVisibilityOnDestroy(); Object::RemoveFromWorld(); @@ -1402,6 +1409,73 @@ bool WorldObject::CheckPrivateObjectOwnerVisibility(WorldObject const* seer) con return false; } +void WorldObject::SetReplacedObject(ObjectGuid const& seer, ObjectGuid const& replacedObject, bool stopAnimKits) +{ + ReplaceObjectInfo replaceObjectInfo; + replaceObjectInfo.ReplaceObject = replacedObject; + replaceObjectInfo.StopAnimKits = stopAnimKits; + _replacedObjects[seer] = replaceObjectInfo; +} + +void WorldObject::ReplaceWith(WorldObject const* seer, WorldObject* replaceWithObject, bool stopAnimKits) +{ + _objectsWhichReplaceMeForSeer[seer->GetGUID()] = replaceWithObject->GetGUID(); + replaceWithObject->SetReplacedObject(seer->GetGUID(), GetGUID(), stopAnimKits); +} + +void WorldObject::ReplaceWith(ObjectGuid const& seerGuid, ObjectGuid const& replaceWithObjectGuid, bool stopAnimKits /*=true*/) +{ + WorldObject* replaceWithObject = ObjectAccessor::GetWorldObject(*this, replaceWithObjectGuid); + if (!replaceWithObject) + return; + + _objectsWhichReplaceMeForSeer[seerGuid] = replaceWithObjectGuid; + replaceWithObject->SetReplacedObject(seerGuid, GetGUID(), stopAnimKits); +} + +void WorldObject::RestoreReplacedObject() +{ + if (_replacedObjects.empty() || !IsPrivateObject()) + return; + + std::unordered_map<ObjectGuid, ReplaceObjectInfo>::iterator itr = _replacedObjects.begin(); + WorldObject* replacedObject = ObjectAccessor::GetWorldObject(*this, itr->second.ReplaceObject); + if (!replacedObject) + return; + + ReplaceWith(itr->first, itr->second.ReplaceObject, itr->second.StopAnimKits); + replacedObject->RemoveObjectWhichReplacesMe(itr->first); + _replacedObjects.erase(itr->first); + + Player* player = ObjectAccessor::FindPlayer(itr->first); + if (!player) + return; + + WorldObject* targets[] = { replacedObject, this }; + player->UpdateVisibilityOf({ std::begin(targets), std::end(targets) }); +} + +ReplaceObjectInfo const* WorldObject::GetReplacedObjectFor(WorldObject const* seer) const +{ + auto itr = _replacedObjects.find(seer->GetGUID()); + if (itr != _replacedObjects.end()) + return &itr->second; + + return nullptr; +} + +bool WorldObject::CheckReplacedObjectVisibility(WorldObject const* seer) const +{ + if (Creature const* creature = ToCreature()) + { + Player const* player = seer->ToPlayer(); + if (player && IsBeingReplacedFor(player)) + return false; + } + + return true; +} + bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, bool distanceCheck, bool checkAlert) const { if (this == obj) @@ -1416,6 +1490,9 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo if (!obj->CheckPrivateObjectOwnerVisibility(this)) return false; + if (!obj->CheckReplacedObjectVisibility(this)) + return false; + if (!sConditionMgr->IsObjectMeetingVisibilityByObjectIdConditions(obj->GetTypeId(), obj->GetEntry(), const_cast<WorldObject*>(this))) return false; @@ -1712,7 +1789,7 @@ void WorldObject::AddObjectToRemoveList() map->AddObjectToRemoveList(this); } -TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/) +TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, ObjectGuid privateObjectOwner /*= ObjectGuid::Empty*/, ObjectGuid replaceObject /* = ObjectGuid::Empty */) { uint32 mask = UNIT_MASK_SUMMON; if (properties) @@ -1762,6 +1839,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } } + if (WorldObject* objectOwner = ObjectAccessor::GetWorldObject(*summoner, privateObjectOwner)) + summoner = objectOwner; + Unit* summonerUnit = summoner ? summoner->ToUnit() : nullptr; TempSummon* summon = nullptr; @@ -1801,7 +1881,15 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert summon->SetPrivateObjectOwner(privateObjectOwner); - AddToMap(summon->ToCreature()); + if (summoner && !replaceObject.IsEmpty()) + PhasingHandler::ReplaceObject(summoner, summon, replaceObject); + + if (!AddToMap(summon->ToCreature())) + { + delete summon; + return nullptr; + } + summon->InitSummon(); // call MoveInLineOfSight for nearby creatures @@ -1882,7 +1970,7 @@ TempSummon* WorldObject::SummonPersonalClone(Position const& pos, TempSummonType { if (Map* map = FindMap()) { - if (TempSummon* summon = map->SummonCreature(GetEntry(), pos, nullptr, despawnTime.count(), this, spellId, vehId, privateObjectOwner)) + if (TempSummon* summon = map->SummonCreature(GetEntry(), pos, nullptr, despawnTime.count(), this, spellId, vehId, privateObjectOwner, GetGUID())) { summon->SetTempSummonType(despawnType); return summon; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 7068f7e73bf..a71bb7b5e75 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -370,7 +370,7 @@ class TC_GAME_API Object } } - void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags) const; + void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player* target) const; virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const; virtual void BuildValuesCreate(ByteBuffer* data, Player const* target) const = 0; virtual void BuildValuesUpdate(ByteBuffer* data, Player const* target) const = 0; @@ -438,6 +438,12 @@ class FlaggedValuesArray32 T_FLAGS m_flags; }; +struct TC_GAME_API ReplaceObjectInfo +{ + ObjectGuid ReplaceObject; + bool StopAnimKits = true; +}; + class TC_GAME_API WorldObject : public Object, public WorldLocation { protected: @@ -725,6 +731,21 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void SetPrivateObjectOwner(ObjectGuid const& owner) { _privateObjectOwner = owner; } bool CheckPrivateObjectOwnerVisibility(WorldObject const* seer) const; + // Smooth Phasing + void ReplaceWith(ObjectGuid const& seerGuid, ObjectGuid const& replaceWithObjectGuid, bool stopAnimKits = true); + void ReplaceWith(WorldObject const* seer, WorldObject* replaceWithObject, bool stopAnimKits = true); + void SetReplacedObject(ObjectGuid const& seer, ObjectGuid const& replacedObject, bool stopAnimKits = true); + void RestoreReplacedObject(); + void RemoveObjectWhichReplacesMe(WorldObject const* seer) { RemoveObjectWhichReplacesMe(seer->GetGUID()); } + void RemoveObjectWhichReplacesMe(ObjectGuid const& seerGuid) { _objectsWhichReplaceMeForSeer.erase(seerGuid); } + // If Me is replacing any other creature + ReplaceObjectInfo const* GetReplacedObjectFor(WorldObject const* seer) const; + bool IsReplacingObjectFor(WorldObject const* seer) const { return GetReplacedObjectFor(seer) != nullptr; } + // If Me is replaced for player x by any other creature + bool IsBeingReplacedFor(WorldObject const* seer) const { return _objectsWhichReplaceMeForSeer.find(seer->GetGUID()) != _objectsWhichReplaceMeForSeer.end(); } + + bool CheckReplacedObjectVisibility(WorldObject const* seer) const; + protected: std::string m_name; bool m_isActive; @@ -766,6 +787,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation ObjectGuid _privateObjectOwner; + std::unordered_map<ObjectGuid /* Seer */, ReplaceObjectInfo> _replacedObjects; + std::unordered_map<ObjectGuid /* Seer */, ObjectGuid /* Object which is replacing me */> _objectsWhichReplaceMeForSeer; + virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius = true, bool incTargetRadius = true) const; bool CanNeverSee(WorldObject const* obj) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 36892a3bd4b..85cadfbc429 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -24177,6 +24177,30 @@ inline void BeforeVisibilityDestroy<Creature>(Creature* t, Player* p) t->ToPet()->Remove(PET_SAVE_NOT_IN_SLOT, true); } +void Player::UpdateVisibilityOf(Trinity::IteratorPair<WorldObject**> targets) +{ + if (targets.begin() == targets.end()) + return; + + UpdateData udata(GetMapId()); + std::set<Unit*> visibleNow; + + for (WorldObject* target : targets) + { + UpdateVisibilityOf(target, udata, visibleNow); + } + + if (!udata.HasData()) + return; + + WorldPacket packet; + udata.BuildPacket(&packet); + SendDirectMessage(&packet); + + for (std::set<Unit*>::const_iterator it = visibleNow.begin(); it != visibleNow.end(); ++it) + SendInitialVisiblePackets(*it); +} + void Player::UpdateVisibilityOf(WorldObject* target) { if (HaveAtClient(target)) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 76d1482bc42..d7ef33b7f73 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2426,6 +2426,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateObjectVisibility(bool forced = true) override; void UpdateVisibilityForPlayer(); void UpdateVisibilityOf(WorldObject* target); + void UpdateVisibilityOf(Trinity::IteratorPair<WorldObject**> targets); void UpdateTriggerVisibility(); template<class T> diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 80080876d02..470a4a16464 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -448,7 +448,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> void UpdateIteratorBack(Player* player); - TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty); + TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0, ObjectGuid privateObjectOwner = ObjectGuid::Empty, ObjectGuid replaceObject = ObjectGuid::Empty); void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr); AreaTrigger* GetAreaTrigger(ObjectGuid const& guid); SceneObject* GetSceneObject(ObjectGuid const& guid); diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp index 50e7afe586f..974461141a3 100644 --- a/src/server/game/Phasing/PhasingHandler.cpp +++ b/src/server/game/Phasing/PhasingHandler.cpp @@ -670,6 +670,20 @@ bool PhasingHandler::IsPersonalPhase(uint32 phaseId) return false; } +void PhasingHandler::ReplaceObject(WorldObject* object, WorldObject* newObject, ObjectGuid const& replacedObjectGuid, bool stopAnimKits /*= true*/) +{ + WorldObject* replacedObject = ObjectAccessor::GetWorldObject(*object, replacedObjectGuid); + if (!replacedObject) + return; + + replacedObject->ReplaceWith(object, newObject, stopAnimKits); + if (Player* player = object->ToPlayer()) + { + WorldObject* targets[] = { newObject, replacedObject }; + player->UpdateVisibilityOf({ std::begin(targets), std::end(targets) }); + } +} + void PhasingHandler::UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed) { if (changed && object->IsInWorld()) diff --git a/src/server/game/Phasing/PhasingHandler.h b/src/server/game/Phasing/PhasingHandler.h index dfb8eb7aa94..bace95c9fa4 100644 --- a/src/server/game/Phasing/PhasingHandler.h +++ b/src/server/game/Phasing/PhasingHandler.h @@ -74,6 +74,8 @@ public: static bool IsPersonalPhase(uint32 phaseId); + static void ReplaceObject(WorldObject* object, WorldObject* newObject, ObjectGuid const& replacedObjectGuid, bool stopAnimKits = true); + private: class ControlledUnitVisitor; friend ControlledUnitVisitor; |