aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSeyden <saiifii@live.de>2022-01-29 19:44:55 +0100
committerShauren <shauren.trinity@gmail.com>2022-01-29 20:35:25 +0100
commita5c713eaf21ce086074cf5934d1ee105c2c86922 (patch)
tree13d75f04967e9b3f5a64423ca1bd408a6528d98c /src
parent5a82a0381d704e4b4b9976daf04d541d1130e541 (diff)
Core/Objects: Implement SmoothPhasing part of CreateObject and replacing visible objects
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Object/Object.cpp116
-rw-r--r--src/server/game/Entities/Object/Object.h26
-rw-r--r--src/server/game/Entities/Player/Player.cpp24
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Maps/Map.h2
-rw-r--r--src/server/game/Phasing/PhasingHandler.cpp14
-rw-r--r--src/server/game/Phasing/PhasingHandler.h2
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;