aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp4
-rw-r--r--src/server/game/Entities/Account/Account.cpp86
-rw-r--r--src/server/game/Entities/Account/Account.h54
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp5
-rw-r--r--src/server/game/Entities/Conversation/Conversation.cpp2
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp6
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp32
-rw-r--r--src/server/game/Entities/DynamicObject/DynamicObject.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp15
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h2
-rw-r--r--src/server/game/Entities/Item/Container/Bag.cpp2
-rw-r--r--src/server/game/Entities/Item/Item.cpp6
-rw-r--r--src/server/game/Entities/Object/BaseEntity.cpp673
-rw-r--r--src/server/game/Entities/Object/BaseEntity.h419
-rw-r--r--src/server/game/Entities/Object/Object.cpp680
-rw-r--r--src/server/game/Entities/Object/Object.h397
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.h5
-rw-r--r--src/server/game/Entities/Object/SmoothPhasing.cpp7
-rw-r--r--src/server/game/Entities/Object/SmoothPhasing.h7
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateData.cpp28
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateData.h26
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.cpp60
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.h67
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateMask.h10
-rw-r--r--src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.cpp48
-rw-r--r--src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.h84
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp15
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Entities/SceneObject/SceneObject.cpp2
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp11
-rw-r--r--src/server/game/Entities/Unit/Unit.h6
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.cpp12
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h13
-rw-r--r--src/server/game/Maps/Map.cpp2
-rw-r--r--src/server/game/Maps/Map.h7
-rw-r--r--src/server/game/Server/WorldSession.cpp28
-rw-r--r--src/server/game/Server/WorldSession.h24
-rw-r--r--src/server/game/Server/WorldSocket.cpp65
-rw-r--r--src/server/game/World/World.cpp3
41 files changed, 1650 insertions, 1275 deletions
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 5ed330a6c48..820e828003a 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -40,8 +40,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_LOGON, "UPDATE account SET salt = ?, verifier = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id AS aId, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id AS baId, aa.SecurityLevel, "
- "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate AS is_bnet_banned, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate AS is_banned, r.id "
+ PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id AS account_id, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id AS bnet_account_id, ba.email as bnet_account_email, aa.SecurityLevel, "
+ "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate AS is_bnet_banned, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate AS is_banned, r.id AS recruitId "
"FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id "
"LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 "
"WHERE a.username = ? AND LENGTH(a.session_key_bnet) = 64 ORDER BY aa.RealmID DESC LIMIT 1", CONNECTION_ASYNC);
diff --git a/src/server/game/Entities/Account/Account.cpp b/src/server/game/Entities/Account/Account.cpp
new file mode 100644
index 00000000000..1de478212b7
--- /dev/null
+++ b/src/server/game/Entities/Account/Account.cpp
@@ -0,0 +1,86 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Account.h"
+#include "Map.h"
+#include "Player.h"
+#include "StringFormat.h"
+#include "WorldSession.h"
+
+namespace Battlenet
+{
+Account::Account(WorldSession* session, ObjectGuid guid, std::string&& name) : m_session(session), m_name(std::move(name))
+{
+ _Create(guid);
+
+ m_entityFragments.Add(WowCS::EntityFragment::FHousingStorage_C, false, WowCS::FragmentSerializationTraits<&Account::m_housingStorageData>{});
+
+ // Default value
+ SetUpdateFieldValue(m_values.ModifyValue(&Account::m_housingStorageData).ModifyValue(&UF::HousingStorageData::DecorMaxOwnedCount), 5000);
+}
+
+void Account::ClearUpdateMask(bool remove)
+{
+ m_values.ClearChangesMask(&Account::m_housingStorageData);
+ BaseEntity::ClearUpdateMask(remove);
+}
+
+std::string Account::GetNameForLocaleIdx(LocaleConstant /*locale*/) const
+{
+ return m_name;
+}
+
+void Account::BuildUpdate(UpdateDataMapType& data_map)
+{
+ BuildUpdateChangesMask();
+
+ if (Player* owner = m_session->GetPlayer())
+ BuildFieldsUpdate(owner, data_map);
+
+ ClearUpdateMask(false);
+}
+
+std::string Account::GetDebugInfo() const
+{
+ return Trinity::StringFormat("{}\nName: {}", BaseEntity::GetDebugInfo(), m_name);
+}
+
+UF::UpdateFieldFlag Account::GetUpdateFieldFlagsFor(Player const* target) const
+{
+ if (*target->m_playerData->BnetAccount == GetGUID())
+ return UF::UpdateFieldFlag::Owner;
+
+ return UF::UpdateFieldFlag::None;
+}
+
+bool Account::AddToObjectUpdate()
+{
+ if (Player* owner = m_session->GetPlayer(); owner && owner->IsInWorld())
+ {
+ owner->GetMap()->AddUpdateObject(this);
+ return true;
+ }
+
+ return false;
+}
+
+void Account::RemoveFromObjectUpdate()
+{
+ if (Player* owner = m_session->GetPlayer(); owner && owner->IsInWorld())
+ owner->GetMap()->RemoveUpdateObject(this);
+}
+}
diff --git a/src/server/game/Entities/Account/Account.h b/src/server/game/Entities/Account/Account.h
new file mode 100644
index 00000000000..3e6f1360e98
--- /dev/null
+++ b/src/server/game/Entities/Account/Account.h
@@ -0,0 +1,54 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TRINITYCORE_ACCOUNT_H
+#define TRINITYCORE_ACCOUNT_H
+
+#include "BaseEntity.h"
+
+class WorldSession;
+
+namespace Battlenet
+{
+class Account final : public BaseEntity
+{
+public:
+ explicit Account(WorldSession* session, ObjectGuid guid, std::string&& name);
+
+ void ClearUpdateMask(bool remove) override;
+
+ std::string GetNameForLocaleIdx(LocaleConstant locale) const override;
+
+ void BuildUpdate(UpdateDataMapType& data_map) override;
+
+ std::string GetDebugInfo() const override;
+
+ UF::UpdateField<UF::HousingStorageData, int32(WowCS::EntityFragment::FHousingStorage_C), 0> m_housingStorageData;
+
+protected:
+ UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const override;
+
+ bool AddToObjectUpdate() override;
+ void RemoveFromObjectUpdate() override;
+
+private:
+ WorldSession* m_session;
+ std::string m_name;
+};
+}
+
+#endif // TRINITYCORE_ACCOUNT_H
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index 234a03aa9d0..1a97401096a 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -138,7 +138,7 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti
_areaTriggerTemplate = _areaTriggerCreateProperties->Template;
- Object::_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
+ _Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
if (GetTemplate())
SetEntry(GetTemplate()->Id.Id);
@@ -235,7 +235,10 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti
}
if (target && HasAreaTriggerFlag(AreaTriggerFieldFlags::Attached))
+ {
m_movementInfo.transport.guid = target->GetGUID();
+ m_updateFlag.MovementTransport = true;
+ }
if (!IsStaticSpawn())
UpdatePositionData();
diff --git a/src/server/game/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp
index 7891bd9bd68..1900374b243 100644
--- a/src/server/game/Entities/Conversation/Conversation.cpp
+++ b/src/server/game/Entities/Conversation/Conversation.cpp
@@ -176,7 +176,7 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry,
Relocate(pos);
RelocateStationaryPosition(pos);
- Object::_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
+ _Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
PhasingHandler::InheritPhaseShift(this, creator);
UpdatePositionData();
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index 95e8fb5ba0a..3f3038c214c 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -65,7 +65,7 @@ void Corpse::RemoveFromWorld()
bool Corpse::Create(ObjectGuid::LowType guidlow, Map* map)
{
- Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(map->GetId(), 0, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Corpse>(map->GetId(), 0, guidlow));
return true;
}
@@ -82,7 +82,7 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner)
return false;
}
- Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(owner->GetMapId(), 0, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Corpse>(owner->GetMapId(), 0, guidlow));
SetObjectScale(1.0f);
SetOwnerGUID(owner->GetGUID());
@@ -190,7 +190,7 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields)
float o = fields[3].GetFloat();
uint32 mapId = fields[4].GetUInt16();
- Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(mapId, 0, guid));
+ _Create(ObjectGuid::Create<HighGuid::Corpse>(mapId, 0, guid));
SetObjectScale(1.0f);
SetDisplayId(fields[5].GetUInt32());
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 739beed45c6..8da8904b845 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1829,9 +1829,9 @@ bool Creature::CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, Creatu
SetOriginalEntry(entry);
if (vehId || cinfo->VehicleId)
- Object::_Create(ObjectGuid::Create<HighGuid::Vehicle>(GetMapId(), entry, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Vehicle>(GetMapId(), entry, guidlow));
else
- Object::_Create(ObjectGuid::Create<HighGuid::Creature>(GetMapId(), entry, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Creature>(GetMapId(), entry, guidlow));
if (!UpdateEntry(entry, data))
return false;
@@ -3297,7 +3297,7 @@ void Creature::SetVendor(NPCFlags flags, bool apply)
if (apply)
{
if (!m_vendorData)
- m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld());
+ m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld(), WowCS::FragmentSerializationTraits<&Creature::m_vendorData>{});
SetNpcFlag(flags);
SetUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(vendorFlags));
@@ -3319,7 +3319,7 @@ void Creature::SetPetitioner(bool apply)
if (apply)
{
if (!m_vendorData)
- m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld());
+ m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld(), WowCS::FragmentSerializationTraits<&Creature::m_vendorData>{});
SetNpcFlag(UNIT_NPC_FLAG_PETITIONER);
SetUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(VendorDataTypeFlags::Petition));
@@ -3868,31 +3868,17 @@ void Creature::BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Pl
{
m_objectData->WriteCreate(*data, flags, this, target);
m_unitData->WriteCreate(*data, flags, this, target);
-
- if (m_vendorData)
- {
- if constexpr (WowCS::IsIndirectFragment(WowCS::EntityFragment::FVendor_C))
- *data << uint8(1); // IndirectFragmentActive: FVendor_C
-
- m_vendorData->WriteCreate(*data, flags, this, target);
- }
}
void Creature::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
{
- if (m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment::CGObject))
- {
- *data << uint32(m_values.GetChangedObjectTypeMask());
-
- if (m_values.HasChanged(TYPEID_OBJECT))
- m_objectData->WriteUpdate(*data, flags, this, target);
+ *data << uint32(m_values.GetChangedObjectTypeMask());
- if (m_values.HasChanged(TYPEID_UNIT))
- m_unitData->WriteUpdate(*data, flags, this, target);
- }
+ if (m_values.HasChanged(TYPEID_OBJECT))
+ m_objectData->WriteUpdate(*data, flags, this, target);
- if (m_vendorData && m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment::FVendor_C))
- m_vendorData->WriteUpdate(*data, flags, this, target);
+ if (m_values.HasChanged(TYPEID_UNIT))
+ m_unitData->WriteUpdate(*data, flags, this, target);
}
void Creature::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
index 4a86d6c0e91..d59de6ae949 100644
--- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
@@ -92,7 +92,7 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste
return false;
}
- WorldObject::_Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow));
PhasingHandler::InheritPhaseShift(this, caster);
UpdatePositionData();
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index d0f8fb33695..00ef5e065c2 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -430,9 +430,9 @@ public:
return 1;
}
- std::vector<uint32> const* GetPauseTimes() const
+ std::span<uint32 const> GetPauseTimes() const
{
- return &_stopFrames;
+ return _stopFrames;
}
ObjectGuid GetTransportGUID() const override { return _owner.GetGUID(); }
@@ -1023,7 +1023,7 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
m_updateFlag.ServerTime = true;
}
- Object::_Create(guid);
+ _Create(guid);
m_goInfo = goInfo;
m_goTemplateAddon = sObjectMgr->GetGameObjectTemplateAddon(entry);
@@ -4136,12 +4136,13 @@ void GameObject::ClearUpdateMask(bool remove)
Object::ClearUpdateMask(remove);
}
-std::vector<uint32> const* GameObject::GetPauseTimes() const
+std::span<uint32 const> GameObject::GetPauseTimes() const
{
+ std::span<uint32 const> result;
if (GameObjectType::Transport const* transport = dynamic_cast<GameObjectType::Transport const*>(m_goTypeImpl.get()))
- return transport->GetPauseTimes();
+ result = transport->GetPauseTimes();
- return nullptr;
+ return result;
}
void GameObject::SetPathProgressForClient(float progress)
@@ -4253,6 +4254,8 @@ void GameObject::SetAnimKitId(uint16 animKitId, bool oneshot)
else
_animKitId = 0;
+ m_updateFlag.AnimKit = _animKitId != 0;
+
WorldPackets::GameObject::GameObjectActivateAnimKit activateAnimKit;
activateAnimKit.ObjectGUID = GetGUID();
activateAnimKit.AnimKitID = animKitId;
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 800ef83a09e..5b1ed3b0b0b 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -290,7 +290,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void SetGoAnimProgress(uint8 animprogress) { SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::PercentHealth), animprogress); }
static void SetGoArtKit(uint32 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0));
- std::vector<uint32> const* GetPauseTimes() const;
+ std::span<uint32 const> GetPauseTimes() const;
Optional<float> GetPathProgressForClient() const { return m_transportPathProgress; }
void SetPathProgressForClient(float progress);
diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp
index 15d5c6795b2..70ae39e471f 100644
--- a/src/server/game/Entities/Item/Container/Bag.cpp
+++ b/src/server/game/Entities/Item/Container/Bag.cpp
@@ -75,7 +75,7 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, ItemContext context
if (!itemProto || itemProto->GetContainerSlots() > MAX_BAG_SIZE)
return false;
- Object::_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
_bonusData.Initialize(itemProto);
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index cb7bdad249b..5bbd1b81edb 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -506,7 +506,7 @@ Item::~Item() = default;
bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext context, Player const* owner)
{
- Object::_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
SetEntry(itemId);
SetObjectScale(1.0f);
@@ -922,7 +922,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
// create item before any checks for store correct guid
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
- Object::_Create(ObjectGuid::Create<HighGuid::Item>(guid));
+ _Create(ObjectGuid::Create<HighGuid::Item>(guid));
// Set entry, MUST be before proto check
SetEntry(entry);
@@ -1786,6 +1786,8 @@ bool Item::IsBindedNotWith(Player const* player) const
void Item::BuildUpdate(UpdateDataMapType& data_map)
{
+ BuildUpdateChangesMask();
+
if (Player* owner = GetOwner())
BuildFieldsUpdate(owner, data_map);
ClearUpdateMask(false);
diff --git a/src/server/game/Entities/Object/BaseEntity.cpp b/src/server/game/Entities/Object/BaseEntity.cpp
new file mode 100644
index 00000000000..316ef1b3201
--- /dev/null
+++ b/src/server/game/Entities/Object/BaseEntity.cpp
@@ -0,0 +1,673 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BaseEntity.h"
+#include "Conversation.h"
+#include "DB2Structure.h"
+#include "Errors.h"
+#include "GameTime.h"
+#include "Log.h"
+#include "MovementPackets.h"
+#include "Player.h"
+#include "SmoothPhasing.h"
+#include "Transport.h"
+#include "UpdateData.h"
+#include "Vehicle.h"
+
+BaseEntity::BaseEntity() = default;
+
+BaseEntity::~BaseEntity()
+{
+ if (IsInWorld())
+ {
+ TC_LOG_FATAL("misc", "BaseEntity::~BaseEntity {} deleted but still in world!!", GetGUID());
+ ABORT();
+ }
+
+ if (m_objectUpdated)
+ {
+ TC_LOG_FATAL("misc", "BaseEntity::~BaseEntity {} deleted but still in update list!!", GetGUID());
+ ABORT();
+ }
+}
+
+void BaseEntity::AddToWorld()
+{
+ if (m_inWorld)
+ return;
+
+ m_inWorld = true;
+
+ // synchronize values mirror with values array (changes will send in updatecreate opcode any way
+ ASSERT(!m_objectUpdated);
+ ClearUpdateMask(false);
+}
+
+void BaseEntity::RemoveFromWorld()
+{
+ if (!m_inWorld)
+ return;
+
+ m_inWorld = false;
+
+ // if we remove from world then sending changes not required
+ ClearUpdateMask(true);
+}
+
+void BaseEntity::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
+{
+ if (!target)
+ return;
+
+ uint8 updateType = m_isNewObject ? UPDATETYPE_CREATE_OBJECT2 : UPDATETYPE_CREATE_OBJECT;
+ uint8 objectType = m_objectTypeId;
+ CreateObjectBits flags = m_updateFlag;
+
+ if (target == this) // building packet for yourself
+ {
+ flags.ThisIsYou = true;
+ flags.ActivePlayer = true;
+ objectType = TYPEID_ACTIVE_PLAYER;
+ }
+
+ if (IsWorldObject())
+ {
+ WorldObject const* worldObject = static_cast<WorldObject const*>(this);
+ if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
+ flags.SmoothPhasing = true;
+ }
+
+ ByteBuffer& buf = data->GetBuffer();
+ buf << uint8(updateType);
+ buf << GetGUID();
+ buf << uint8(objectType);
+
+ BuildMovementUpdate(&buf, flags, target);
+
+ UF::UpdateFieldFlag fieldFlags = GetUpdateFieldFlagsFor(target);
+ std::size_t sizePos = buf.wpos();
+ buf << uint32(0);
+ buf << uint8(fieldFlags);
+ BuildEntityFragments(&buf, m_entityFragments.GetIds());
+
+ for (std::size_t i = 0; i < m_entityFragments.UpdateableCount; ++i)
+ {
+ WowCS::EntityFragment fragmentId = m_entityFragments.Updateable.Ids[i];
+ if (WowCS::IsIndirectFragment(fragmentId))
+ buf << uint8(1); // IndirectFragmentActive
+
+ m_entityFragments.Updateable.SerializeCreate[i](this, buf, fieldFlags, target);
+ }
+
+ buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
+
+ data->AddUpdateBlock();
+}
+
+void BaseEntity::SendUpdateToPlayer(Player* player) const
+{
+ // send create update to player
+ UpdateData upd(player->GetMapId());
+ WorldPacket packet;
+
+ if (player->HaveAtClient(this))
+ BuildValuesUpdateBlockForPlayer(&upd, player);
+ else
+ BuildCreateUpdateBlockForPlayer(&upd, player);
+ upd.BuildPacket(&packet);
+ player->SendDirectMessage(&packet);
+}
+
+void BaseEntity::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const
+{
+ ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
+
+ EnumFlag<UF::UpdateFieldFlag> fieldFlags = GetUpdateFieldFlagsFor(target);
+ std::size_t sizePos = buf.wpos();
+ buf << uint32(0);
+ buf << uint8(fieldFlags.HasFlag(UF::UpdateFieldFlag::Owner));
+ buf << uint8(m_entityFragments.IdsChanged);
+ if (m_entityFragments.IdsChanged)
+ {
+ buf << uint8(WowCS::EntityFragmentSerializationType::Full);
+ BuildEntityFragments(&buf, m_entityFragments.GetIds());
+ }
+ buf << uint8(m_entityFragments.ContentsChangedMask);
+
+ for (std::size_t i = 0; i < m_entityFragments.UpdateableCount; ++i)
+ {
+ if (!(m_entityFragments.ContentsChangedMask & m_entityFragments.Updateable.Masks[i]))
+ continue;
+
+ m_entityFragments.Updateable.SerializeUpdate[i](this, buf, fieldFlags, target);
+ }
+
+ buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
+
+ data->AddUpdateBlock();
+}
+
+inline void BaseEntity::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
+{
+ data->append(fragments.data(), fragments.size());
+ *data << uint8(WowCS::EntityFragment::End);
+}
+
+void BaseEntity::BuildDestroyUpdateBlock(UpdateData* data) const
+{
+ data->AddDestroyObject(GetGUID());
+}
+
+void BaseEntity::BuildOutOfRangeUpdateBlock(UpdateData* data) const
+{
+ data->AddOutOfRangeGUID(GetGUID());
+}
+
+ByteBuffer& BaseEntity::PrepareValuesUpdateBuffer(UpdateData* data) const
+{
+ ByteBuffer& buffer = data->GetBuffer();
+ buffer << uint8(UPDATETYPE_VALUES);
+ buffer << GetGUID();
+ return buffer;
+}
+
+void BaseEntity::DestroyForPlayer(Player const* target) const
+{
+ ASSERT(target);
+
+ UpdateData updateData(target->GetMapId());
+ BuildDestroyUpdateBlock(&updateData);
+ WorldPacket packet;
+ updateData.BuildPacket(&packet);
+ target->SendDirectMessage(&packet);
+}
+
+void BaseEntity::SendOutOfRangeForPlayer(Player const* target) const
+{
+ ASSERT(target);
+
+ UpdateData updateData(target->GetMapId());
+ BuildOutOfRangeUpdateBlock(&updateData);
+ WorldPacket packet;
+ updateData.BuildPacket(&packet);
+ target->SendDirectMessage(&packet);
+}
+
+void BaseEntity::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const
+{
+ std::span<uint32 const> PauseTimes;
+ if (IsGameObject())
+ PauseTimes = static_cast<GameObject const*>(this)->GetPauseTimes();
+
+ data->WriteBit(flags.HasEntityPosition);
+ data->WriteBit(flags.NoBirthAnim);
+ data->WriteBit(flags.EnablePortals);
+ data->WriteBit(flags.PlayHoverAnim);
+ data->WriteBit(flags.ThisIsYou);
+ data->WriteBit(flags.MovementUpdate);
+ data->WriteBit(flags.MovementTransport);
+ data->WriteBit(flags.Stationary);
+ data->WriteBit(flags.CombatVictim);
+ data->WriteBit(flags.ServerTime);
+ data->WriteBit(flags.Vehicle);
+ data->WriteBit(flags.AnimKit);
+ data->WriteBit(flags.Rotation);
+ data->WriteBit(flags.GameObject);
+ data->WriteBit(flags.SmoothPhasing);
+ data->WriteBit(flags.SceneObject);
+ data->WriteBit(flags.ActivePlayer);
+ data->WriteBit(flags.Conversation);
+ data->WriteBit(flags.Room);
+ data->WriteBit(flags.Decor);
+ data->WriteBit(flags.MeshObject);
+ data->FlushBits();
+
+ if (flags.MovementUpdate)
+ {
+ Unit const* unit = static_cast<Unit const*>(this);
+ bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
+ bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
+ bool HasSpline = unit->IsSplineEnabled();
+ bool HasInertia = unit->m_movementInfo.inertia.has_value();
+ bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value();
+ bool HasDriveStatus = unit->m_movementInfo.driveStatus.has_value();
+ bool HasStandingOnGameObjectGUID = unit->m_movementInfo.standingOnGameObjectGUID.has_value();
+
+ *data << GetGUID(); // MoverGUID
+
+ *data << uint32(unit->GetUnitMovementFlags());
+ *data << uint32(unit->GetExtraUnitMovementFlags());
+ *data << uint32(unit->GetExtraUnitMovementFlags2());
+
+ *data << uint32(unit->m_movementInfo.time); // MoveTime
+ *data << float(unit->GetPositionX());
+ *data << float(unit->GetPositionY());
+ *data << float(unit->GetPositionZ());
+ *data << float(unit->GetOrientation());
+
+ *data << float(unit->m_movementInfo.pitch); // Pitch
+ *data << float(unit->m_movementInfo.stepUpStartElevation); // StepUpStartElevation
+
+ *data << uint32(0); // RemoveForcesIDs.size()
+ *data << uint32(0); // MoveIndex
+
+ //for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
+ // *data << ObjectGuid(RemoveForcesIDs);
+
+ data->WriteBit(HasStandingOnGameObjectGUID); // HasStandingOnGameObjectGUID
+ data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
+ data->WriteBit(HasFall); // HasFall
+ data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
+ data->WriteBit(false); // HeightChangeFailed
+ data->WriteBit(false); // RemoteTimeValid
+ data->WriteBit(HasInertia); // HasInertia
+ data->WriteBit(HasAdvFlying); // HasAdvFlying
+ data->WriteBit(HasDriveStatus); // HasDriveStatus
+ data->FlushBits();
+
+ if (!unit->m_movementInfo.transport.guid.IsEmpty())
+ *data << unit->m_movementInfo.transport;
+
+ if (HasStandingOnGameObjectGUID)
+ *data << *unit->m_movementInfo.standingOnGameObjectGUID;
+
+ if (HasInertia)
+ {
+ *data << unit->m_movementInfo.inertia->id;
+ *data << unit->m_movementInfo.inertia->force.PositionXYZStream();
+ *data << uint32(unit->m_movementInfo.inertia->lifetime);
+ }
+
+ if (HasAdvFlying)
+ {
+ *data << float(unit->m_movementInfo.advFlying->forwardVelocity);
+ *data << float(unit->m_movementInfo.advFlying->upVelocity);
+ }
+
+ if (HasFall)
+ {
+ *data << uint32(unit->m_movementInfo.jump.fallTime); // Time
+ *data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
+
+ if (data->WriteBit(HasFallDirection))
+ {
+ *data << float(unit->m_movementInfo.jump.sinAngle); // Direction
+ *data << float(unit->m_movementInfo.jump.cosAngle);
+ *data << float(unit->m_movementInfo.jump.xyspeed); // Speed
+ }
+ }
+
+ if (HasDriveStatus)
+ {
+ *data << float(unit->m_movementInfo.driveStatus->speed);
+ *data << float(unit->m_movementInfo.driveStatus->movementAngle);
+ data->WriteBit(unit->m_movementInfo.driveStatus->accelerating);
+ data->WriteBit(unit->m_movementInfo.driveStatus->drifting);
+ data->FlushBits();
+ }
+
+ *data << float(unit->GetSpeed(MOVE_WALK));
+ *data << float(unit->GetSpeed(MOVE_RUN));
+ *data << float(unit->GetSpeed(MOVE_RUN_BACK));
+ *data << float(unit->GetSpeed(MOVE_SWIM));
+ *data << float(unit->GetSpeed(MOVE_SWIM_BACK));
+ *data << float(unit->GetSpeed(MOVE_FLIGHT));
+ *data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
+ *data << float(unit->GetSpeed(MOVE_TURN_RATE));
+ *data << float(unit->GetSpeed(MOVE_PITCH_RATE));
+
+ if (MovementForces const* movementForces = unit->GetMovementForces())
+ {
+ *data << uint32(movementForces->GetForces()->size());
+ *data << float(movementForces->GetModMagnitude()); // MovementForcesModMagnitude
+ }
+ else
+ {
+ *data << uint32(0);
+ *data << float(1.0f); // MovementForcesModMagnitude
+ }
+
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_AIR_FRICTION));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_MAX_VEL));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LIFT_COEFFICIENT));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_DOUBLE_JUMP_VEL_MOD));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_GLIDE_START_MIN_HEIGHT));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_ADD_IMPULSE_MAX_SPEED));
+ *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_BANKING_RATE));
+ *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_BANKING_RATE));
+ *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_DOWN));
+ *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_DOWN));
+ *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_UP));
+ *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_UP));
+ *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
+ *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_SURFACE_FRICTION));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_OVER_MAX_DECELERATION));
+ *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LAUNCH_SPEED_COEFFICIENT));
+
+ data->WriteBit(HasSpline);
+ data->FlushBits();
+
+ if (MovementForces const* movementForces = unit->GetMovementForces())
+ for (MovementForce const& force : *movementForces->GetForces())
+ WorldPackets::Movement::CommonMovement::WriteMovementForceWithDirection(force, *data, unit);
+
+ if (HasSpline)
+ WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
+ }
+
+ *data << uint32(PauseTimes.size());
+
+ if (flags.Stationary)
+ {
+ WorldObject const* self = static_cast<WorldObject const*>(this);
+ *data << self->GetStationaryPosition().PositionXYZOStream();
+ }
+
+ if (flags.CombatVictim)
+ {
+ Unit const* unit = static_cast<Unit const*>(this);
+ *data << unit->GetVictim()->GetGUID(); // CombatVictim
+ }
+
+ if (flags.ServerTime)
+ *data << uint32(GameTime::GetGameTimeMS());
+
+ if (flags.Vehicle)
+ {
+ Unit const* unit = static_cast<Unit const*>(this);
+ *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
+ *data << float(unit->GetOrientation()); // InitialRawFacing
+ }
+
+ if (flags.AnimKit)
+ {
+ WorldObject const* self = static_cast<WorldObject const*>(this);
+ *data << uint16(self->GetAIAnimKitId()); // AiID
+ *data << uint16(self->GetMovementAnimKitId()); // MovementID
+ *data << uint16(self->GetMeleeAnimKitId()); // MeleeID
+ }
+
+ if (flags.Rotation)
+ {
+ GameObject const* gameObject = static_cast<GameObject const*>(this);
+ *data << uint64(gameObject->GetPackedLocalRotation()); // Rotation
+ }
+
+ //if (flags.Room)
+ // *data << ObjectGuid(HouseGUID);
+
+ //if (flags.Decor)
+ // *data << ObjectGuid(RoomGUID);
+
+ //if (flags.MeshObject)
+ //{
+ // *data << ObjectGuid(AttachParentGUID);
+ // *data << TaggedPosition<Position::XYZ>(PositionLocalSpace);
+ // *data << QuaternionData(RotationLocalSpace);
+ // *data << float(ScaleLocalSpace);
+ // *data << uint8(AttachmentFlags);
+ //}
+
+ if (!PauseTimes.empty())
+ data->append(PauseTimes.data(), PauseTimes.size());
+
+ if (flags.MovementTransport)
+ {
+ WorldObject const* self = static_cast<WorldObject const*>(this);
+ *data << self->m_movementInfo.transport;
+ }
+
+ if (flags.GameObject)
+ {
+ GameObject const* gameObject = static_cast<GameObject const*>(this);
+
+ bool bit8 = false;
+ bool isTransport = gameObject->GetGOInfo()->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT;
+
+ *data << uint32(gameObject->GetWorldEffectID());
+
+ data->WriteBit(bit8);
+ data->WriteBit(isTransport);
+ data->WriteBit(gameObject->GetPathProgressForClient().has_value());
+ data->FlushBits();
+ if (isTransport)
+ {
+ Transport const* transport = static_cast<Transport const*>(gameObject);
+ uint32 period = transport->GetTransportPeriod();
+
+ *data << uint32((((int64(transport->GetTimer()) - int64(GameTime::GetGameTimeMS())) % period) + period) % period); // TimeOffset
+ *data << uint32(transport->GetNextStopTimestamp().value_or(0));
+ data->WriteBit(transport->GetNextStopTimestamp().has_value());
+ data->WriteBit(transport->IsStopped());
+ data->WriteBit(false);
+ data->FlushBits();
+ }
+
+ if (bit8)
+ *data << uint32(0);
+
+ if (gameObject->GetPathProgressForClient())
+ *data << float(*gameObject->GetPathProgressForClient());
+ }
+
+ if (flags.SmoothPhasing)
+ {
+ SmoothPhasingInfo const* smoothPhasingInfo = static_cast<WorldObject const*>(this)->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID());
+ ASSERT(smoothPhasingInfo);
+
+ data->WriteBit(smoothPhasingInfo->ReplaceActive);
+ data->WriteBit(smoothPhasingInfo->StopAnimKits);
+ data->WriteBit(smoothPhasingInfo->ReplaceObject.has_value());
+ data->FlushBits();
+ if (smoothPhasingInfo->ReplaceObject)
+ *data << *smoothPhasingInfo->ReplaceObject;
+ }
+
+ if (flags.SceneObject)
+ {
+ data->WriteBit(false); // HasLocalScriptData
+ data->WriteBit(false); // HasPetBattleFullUpdate
+ data->FlushBits();
+
+ // if (HasLocalScriptData)
+ // {
+ // data->WriteBits(Data.length(), 7);
+ // data->FlushBits();
+ // data->WriteString(Data);
+ // }
+
+ // if (HasPetBattleFullUpdate)
+ // {
+ // for (std::size_t i = 0; i < 2; ++i)
+ // {
+ // *data << ObjectGuid(Players[i].CharacterID);
+ // *data << int32(Players[i].TrapAbilityID);
+ // *data << int32(Players[i].TrapStatus);
+ // *data << uint16(Players[i].RoundTimeSecs);
+ // *data << int8(Players[i].FrontPet);
+ // *data << uint8(Players[i].InputFlags);
+
+ // data->WriteBits(Players[i].Pets.size(), 2);
+ // data->FlushBits();
+ // for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
+ // {
+ // *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
+ // *data << int32(Players[i].Pets[j].SpeciesID);
+ // *data << int32(Players[i].Pets[j].CreatureID);
+ // *data << int32(Players[i].Pets[j].DisplayID);
+ // *data << int16(Players[i].Pets[j].Level);
+ // *data << int16(Players[i].Pets[j].Xp);
+ // *data << int32(Players[i].Pets[j].CurHealth);
+ // *data << int32(Players[i].Pets[j].MaxHealth);
+ // *data << int32(Players[i].Pets[j].Power);
+ // *data << int32(Players[i].Pets[j].Speed);
+ // *data << int32(Players[i].Pets[j].NpcTeamMemberID);
+ // *data << uint8(Players[i].Pets[j].BreedQuality);
+ // *data << uint16(Players[i].Pets[j].StatusFlags);
+ // *data << int8(Players[i].Pets[j].Slot);
+
+ // *data << uint32(Players[i].Pets[j].Abilities.size());
+ // *data << uint32(Players[i].Pets[j].Auras.size());
+ // *data << uint32(Players[i].Pets[j].States.size());
+ // for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
+ // {
+ // *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
+ // *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
+ // *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
+ // *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
+ // *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
+ // }
+
+ // for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
+ // {
+ // *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
+ // *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
+ // *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
+ // *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
+ // *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
+ // }
+
+ // for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
+ // {
+ // *data << uint32(Players[i].Pets[j].States[k].StateID);
+ // *data << int32(Players[i].Pets[j].States[k].StateValue);
+ // }
+
+ // data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
+ // data->FlushBits();
+ // data->WriteString(Players[i].Pets[j].CustomName);
+ // }
+ // }
+
+ // for (std::size_t i = 0; i < 3; ++i)
+ // {
+ // *data << uint32(Enviros[j].Auras.size());
+ // *data << uint32(Enviros[j].States.size());
+ // for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
+ // {
+ // *data << int32(Enviros[j].Auras[j].AbilityID);
+ // *data << uint32(Enviros[j].Auras[j].InstanceID);
+ // *data << int32(Enviros[j].Auras[j].RoundsRemaining);
+ // *data << int32(Enviros[j].Auras[j].CurrentRound);
+ // *data << uint8(Enviros[j].Auras[j].CasterPBOID);
+ // }
+
+ // for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
+ // {
+ // *data << uint32(Enviros[i].States[j].StateID);
+ // *data << int32(Enviros[i].States[j].StateValue);
+ // }
+ // }
+
+ // *data << uint16(WaitingForFrontPetsMaxSecs);
+ // *data << uint16(PvpMaxRoundTime);
+ // *data << int32(CurRound);
+ // *data << uint32(NpcCreatureID);
+ // *data << uint32(NpcDisplayID);
+ // *data << int8(CurPetBattleState);
+ // *data << uint8(ForfeitPenalty);
+ // *data << ObjectGuid(InitialWildPetGUID);
+ // data->WriteBit(IsPVP);
+ // data->WriteBit(CanAwardXP);
+ // data->FlushBits();
+ // }
+ }
+
+ if (flags.ActivePlayer)
+ {
+ Player const* player = static_cast<Player const*>(this);
+
+ bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty();
+ bool HasRuneState = player->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
+
+ data->WriteBit(HasSceneInstanceIDs);
+ data->WriteBit(HasRuneState);
+ data->FlushBits();
+ if (HasSceneInstanceIDs)
+ {
+ *data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size());
+ for (auto const& [sceneInstanceId, _] : player->GetSceneMgr().GetSceneTemplateByInstanceMap())
+ *data << uint32(sceneInstanceId);
+ }
+ if (HasRuneState)
+ {
+ float baseCd = float(player->GetRuneBaseCooldown());
+ uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
+
+ *data << uint8((1 << maxRunes) - 1);
+ *data << uint8(player->GetRunesState());
+ *data << uint32(maxRunes);
+ for (uint32 i = 0; i < maxRunes; ++i)
+ *data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
+ }
+ }
+
+ if (flags.Conversation)
+ {
+ Conversation const* self = static_cast<Conversation const*>(this);
+ if (data->WriteBit(self->GetTextureKitId() != 0))
+ *data << uint32(self->GetTextureKitId());
+
+ data->FlushBits();
+ }
+}
+
+UF::UpdateFieldFlag BaseEntity::GetUpdateFieldFlagsFor(Player const* /*target*/) const
+{
+ return UF::UpdateFieldFlag::None;
+}
+
+void BaseEntity::AddToObjectUpdateIfNeeded()
+{
+ if (m_inWorld && !m_objectUpdated)
+ m_objectUpdated = AddToObjectUpdate();
+}
+
+void BaseEntity::ClearUpdateMask(bool remove)
+{
+ m_entityFragments.IdsChanged = false;
+
+ if (m_objectUpdated)
+ {
+ if (remove)
+ RemoveFromObjectUpdate();
+ m_objectUpdated = false;
+ }
+}
+
+void BaseEntity::BuildUpdateChangesMask()
+{
+ for (std::size_t i = 0; i < m_entityFragments.UpdateableCount; ++i)
+ {
+ if (m_entityFragments.Updateable.IsChanged[i](this))
+ m_entityFragments.ContentsChangedMask |= m_entityFragments.Updateable.Masks[i];
+ else
+ m_entityFragments.ContentsChangedMask &= ~m_entityFragments.Updateable.Masks[i];
+ }
+}
+
+void BaseEntity::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
+{
+ UpdateDataMapType::iterator iter = data_map.emplace(player, player->GetMapId()).first;
+ BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
+}
+
+std::string BaseEntity::GetDebugInfo() const
+{
+ return Trinity::StringFormat("{}", GetGUID());
+}
diff --git a/src/server/game/Entities/Object/BaseEntity.h b/src/server/game/Entities/Object/BaseEntity.h
new file mode 100644
index 00000000000..3a3976fc297
--- /dev/null
+++ b/src/server/game/Entities/Object/BaseEntity.h
@@ -0,0 +1,419 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRINITYCORE_BASE_ENTITY_H
+#define TRINITYCORE_BASE_ENTITY_H
+
+#include "Common.h"
+#include "ObjectGuid.h"
+#include "UpdateFields.h"
+#include "WowCSEntityDefinitions.h"
+#include <unordered_map>
+
+class BaseEntity;
+class Player;
+class UpdateData;
+class WorldPacket;
+
+typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
+
+struct CreateObjectBits
+{
+ bool HasEntityPosition : 1;
+ bool NoBirthAnim : 1;
+ bool EnablePortals : 1;
+ bool PlayHoverAnim : 1;
+ bool ThisIsYou : 1;
+ bool MovementUpdate : 1;
+ bool MovementTransport : 1;
+ bool Stationary : 1;
+ bool CombatVictim : 1;
+ bool ServerTime : 1;
+ bool Vehicle : 1;
+ bool AnimKit : 1;
+ bool Rotation : 1;
+ bool GameObject : 1;
+ bool SmoothPhasing : 1;
+ bool SceneObject : 1;
+ bool ActivePlayer : 1;
+ bool Conversation : 1;
+ bool Room : 1;
+ bool Decor : 1;
+ bool MeshObject : 1;
+
+ void Clear()
+ {
+ memset(this, 0, sizeof(CreateObjectBits));
+ }
+};
+
+namespace UF
+{
+ class UpdateFieldHolder
+ {
+ public:
+ template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
+ inline MutableFieldReference<T, false> ModifyValue(UpdateField<T, BlockBit, Bit>(Derived::* field));
+
+ template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
+ inline OptionalUpdateFieldSetter<T> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
+
+ template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
+ inline MutableFieldReference<T, false> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field), uint32 /*dummy*/);
+
+ template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
+ inline void ClearChangesMask(UpdateField<T, BlockBit, Bit>(Derived::* field));
+
+ template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
+ inline void ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
+
+ uint32 GetChangedObjectTypeMask() const { return _changesMask; }
+
+ bool HasChanged(uint32 index) const { return (_changesMask & UpdateMaskHelpers::GetBlockFlag(index)) != 0; }
+
+ inline BaseEntity* GetOwner();
+
+ private:
+ friend BaseEntity;
+
+ // This class is tightly tied to BaseEntity::m_values member, do not construct elsewhere
+ UpdateFieldHolder() = default;
+
+ uint32 _changesMask = 0; // changes mask for data of Object subclasses
+ };
+
+ template<typename T>
+ inline bool SetUpdateFieldValue(UpdateFieldPrivateSetter<T>& setter, typename UpdateFieldPrivateSetter<T>::value_type&& value)
+ {
+ return setter.SetValue(std::move(value));
+ }
+
+ template<typename T>
+ inline typename DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter)
+ {
+ return setter.AddValue();
+ }
+
+ template<typename T>
+ inline typename DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
+ {
+ return setter.InsertValue(index);
+ }
+
+ template<typename T>
+ inline void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
+ {
+ setter.RemoveValue(index);
+ }
+
+ template<typename T>
+ inline void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter<T>& setter)
+ {
+ setter.Clear();
+ }
+
+ template<typename K, typename V>
+ inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
+ {
+ setter.RemoveKey(key);
+ }
+
+ template<typename T>
+ inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
+ {
+ setter.RemoveValue();
+ }
+}
+
+class TC_GAME_API BaseEntity
+{
+ ObjectGuid m_guid;
+
+ public:
+ virtual ~BaseEntity();
+
+ bool IsInWorld() const { return m_inWorld; }
+
+ virtual void AddToWorld();
+ virtual void RemoveFromWorld();
+
+ static ObjectGuid GetGUID(BaseEntity const* o) { return o ? o->GetGUID() : ObjectGuid::Empty; }
+ ObjectGuid const& GetGUID() const { return m_guid; }
+
+ TypeID GetTypeId() const { return m_objectTypeId; }
+ bool isType(TypeMask mask) const { return (ObjectTypeMask[m_objectTypeId] & mask) != 0; }
+
+ inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); }
+ inline bool IsItem() const { return isType(TYPEMASK_ITEM); }
+ inline bool IsUnit() const { return isType(TYPEMASK_UNIT); }
+ inline bool IsCreature() const { return GetTypeId() == TYPEID_UNIT; }
+ inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; }
+ inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; }
+ inline bool IsDynObject() const { return GetTypeId() == TYPEID_DYNAMICOBJECT; }
+ inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; }
+ inline bool IsAreaTrigger() const { return GetTypeId() == TYPEID_AREATRIGGER; }
+ inline bool IsSceneObject() const { return GetTypeId() == TYPEID_SCENEOBJECT; }
+ inline bool IsConversation() const { return GetTypeId() == TYPEID_CONVERSATION; }
+ inline bool IsMeshObject() const { return GetTypeId() == TYPEID_MESH_OBJECT; }
+
+ virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
+ void SendUpdateToPlayer(Player* player) const;
+
+ void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const;
+ void BuildDestroyUpdateBlock(UpdateData* data) const;
+ void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
+ ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
+
+ virtual void DestroyForPlayer(Player const* target) const;
+ void SendOutOfRangeForPlayer(Player const* target) const;
+
+ virtual void ClearUpdateMask(bool remove);
+
+ virtual std::string GetNameForLocaleIdx(LocaleConstant locale) const = 0;
+
+ void SetIsNewObject(bool enable) { m_isNewObject = enable; }
+ bool IsDestroyedObject() const { return m_isDestroyedObject; }
+ void SetDestroyedObject(bool destroyed) { m_isDestroyedObject = destroyed; }
+ virtual void BuildUpdate([[maybe_unused]] UpdateDataMapType& data_map) { }
+ void BuildUpdateChangesMask();
+ void BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const;
+
+ friend UF::UpdateFieldHolder;
+ UF::UpdateFieldHolder m_values;
+
+ template<typename T>
+ void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter<T> const& /*setter*/)
+ {
+ AddToObjectUpdateIfNeeded();
+ }
+
+ virtual std::string GetDebugInfo() const;
+
+ protected:
+ BaseEntity();
+
+ void _Create(ObjectGuid const& guid) { m_guid = guid; }
+
+ template<typename T>
+ void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
+ {
+ if (UF::SetUpdateFieldValue(setter, std::move(value)))
+ AddToObjectUpdateIfNeeded();
+ }
+
+ template<typename T>
+ void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
+ {
+ static_assert(std::is_integral_v<T>, "SetUpdateFieldFlagValue must be used with integral types");
+ this->SetUpdateFieldValue(setter, setter.GetValue() | flag);
+ }
+
+ template<typename T>
+ void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
+ {
+ static_assert(std::is_integral_v<T>, "RemoveUpdateFieldFlagValue must be used with integral types");
+ this->SetUpdateFieldValue(setter, setter.GetValue() & ~flag);
+ }
+
+ template<typename T>
+ typename UF::DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter)
+ {
+ AddToObjectUpdateIfNeeded();
+ return UF::AddDynamicUpdateFieldValue(setter);
+ }
+
+ template<typename T>
+ typename UF::DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
+ {
+ AddToObjectUpdateIfNeeded();
+ return UF::InsertDynamicUpdateFieldValue(setter, index);
+ }
+
+ template<typename T>
+ void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
+ {
+ AddToObjectUpdateIfNeeded();
+ UF::RemoveDynamicUpdateFieldValue(setter, index);
+ }
+
+ template<typename K, typename V>
+ void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
+ {
+ AddToObjectUpdateIfNeeded();
+ UF::RemoveMapUpdateFieldValue(setter, key);
+ }
+
+ template<typename T>
+ void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter<T> setter)
+ {
+ AddToObjectUpdateIfNeeded();
+ UF::ClearDynamicUpdateFieldValues(setter);
+ }
+
+ template<typename T>
+ void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter<T> setter)
+ {
+ AddToObjectUpdateIfNeeded();
+ UF::RemoveOptionalUpdateFieldValue(setter);
+ }
+
+ // stat system helpers
+ template<typename T>
+ void SetUpdateFieldStatValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
+ {
+ static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
+ this->SetUpdateFieldValue(setter, std::max(value, T(0)));
+ }
+
+ template<typename T>
+ void ApplyModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type mod, bool apply)
+ {
+ static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
+
+ T value = setter.GetValue();
+ if (apply)
+ value += mod;
+ else
+ value -= mod;
+
+ this->SetUpdateFieldValue(setter, value);
+ }
+
+ template<typename T>
+ void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, float percent, bool apply)
+ {
+ static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
+
+ T value = setter.GetValue();
+
+ // don't want to include Util.h here
+ //ApplyPercentModFloatVar(value, percent, apply);
+ if (percent == -100.0f)
+ percent = -99.99f;
+ value *= (apply ? (100.0f + percent) / 100.0f : 100.0f / (100.0f + percent));
+
+ this->SetUpdateFieldValue(setter, value);
+ }
+
+ template<typename Action>
+ void DoWithSuppressingObjectUpdates(Action&& action)
+ {
+ bool wasUpdatedBeforeAction = m_objectUpdated;
+ action();
+ if (m_objectUpdated && !wasUpdatedBeforeAction)
+ {
+ RemoveFromObjectUpdate();
+ m_objectUpdated = false;
+ }
+ }
+
+ void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const;
+ virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const;
+ static void BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments);
+
+ TypeID m_objectTypeId = static_cast<TypeID>(NUM_CLIENT_OBJECT_TYPES);
+ CreateObjectBits m_updateFlag = {};
+ WowCS::EntityFragmentsHolder m_entityFragments;
+
+ virtual bool AddToObjectUpdate() = 0;
+ virtual void RemoveFromObjectUpdate() = 0;
+ void AddToObjectUpdateIfNeeded();
+
+ bool m_objectUpdated = false;
+
+ private:
+ bool m_inWorld = false;
+ bool m_isNewObject = false;
+ bool m_isDestroyedObject = false;
+
+ BaseEntity(BaseEntity const& right) = delete;
+ BaseEntity(BaseEntity&& right) = delete;
+ BaseEntity& operator=(BaseEntity const& right) = delete;
+ BaseEntity& operator=(BaseEntity&& right) = delete;
+};
+
+inline BaseEntity* UF::UpdateFieldHolder::GetOwner()
+{
+#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+ return reinterpret_cast<BaseEntity*>(reinterpret_cast<std::byte*>(this) - offsetof(BaseEntity, m_values));
+
+#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
+#pragma GCC diagnostic pop
+#endif
+}
+
+template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
+inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(UpdateField<T, BlockBit, Bit> Derived::* field)
+{
+ BaseEntity* owner = GetOwner();
+ if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
+ _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
+
+ return { (static_cast<Derived*>(owner)->*field)._value };
+}
+
+template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
+inline UF::OptionalUpdateFieldSetter<T> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
+{
+ BaseEntity* owner = GetOwner();
+ if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
+ _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
+
+ return { static_cast<Derived*>(owner)->*field };
+}
+
+template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
+inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field, uint32 /*dummy*/)
+{
+ BaseEntity* owner = GetOwner();
+ if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
+ _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
+
+ auto& uf = (static_cast<Derived*>(owner)->*field);
+ if (!uf.has_value())
+ uf.ConstructValue();
+
+ return { *uf._value };
+}
+
+template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
+inline void UF::UpdateFieldHolder::ClearChangesMask(UpdateField<T, BlockBit, Bit> Derived::* field)
+{
+ BaseEntity* owner = GetOwner();
+ if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
+ _changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
+
+ (static_cast<Derived*>(owner)->*field)._value.ClearChangesMask();
+}
+
+template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
+inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
+{
+ BaseEntity* owner = GetOwner();
+ if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
+ _changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
+
+ auto& uf = (static_cast<Derived*>(owner)->*field);
+ if (uf.has_value())
+ uf._value->ClearChangesMask();
+}
+
+#endif // TRINITYCORE_BASE_ENTITY_H
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 48ed667e545..33fc45d5617 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -20,19 +20,16 @@
#include "CellImpl.h"
#include "CinematicMgr.h"
#include "CombatLogPackets.h"
-#include "Common.h"
-#include "Creature.h"
+#include "Corpse.h"
#include "CreatureGroups.h"
#include "DB2Stores.h"
-#include "GameTime.h"
+#include "DynamicObject.h"
+#include "GameObject.h"
#include "GridNotifiersImpl.h"
-#include "G3DPosition.hpp"
#include "InstanceScenario.h"
-#include "Item.h"
#include "Log.h"
+#include "Map.h"
#include "MiscPackets.h"
-#include "MovementPackets.h"
-#include "MovementTypedefs.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
@@ -41,17 +38,14 @@
#include "Player.h"
#include "ReputationMgr.h"
#include "SmoothPhasing.h"
+#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "SpellPackets.h"
#include "TemporarySummon.h"
#include "Totem.h"
-#include "Transport.h"
-#include "Unit.h"
#include "UpdateData.h"
-#include "Util.h"
#include "VMapFactory.h"
-#include "Vehicle.h"
#include "VMapManager.h"
#include "World.h"
#include <G3D/Vector3.h>
@@ -70,49 +64,16 @@ constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max
Object::Object() : m_scriptRef(this, NoopObjectDeleter())
{
m_objectTypeId = TYPEID_OBJECT;
- m_updateFlag.Clear();
- m_entityFragments.Add(WowCS::EntityFragment::CGObject, false);
-
- m_inWorld = false;
- m_isNewObject = false;
- m_isDestroyedObject = false;
- m_objectUpdated = false;
+ m_entityFragments.Add(WowCS::EntityFragment::CGObject, false,
+ &Object::BuildObjectFragmentCreate, &Object::BuildObjectFragmentUpdate, &Object::IsObjectFragmentChanged);
}
-Object::~Object()
-{
- if (IsInWorld())
- {
- TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in world!!", GetGUID().ToString());
- if (Item* item = ToItem())
- TC_LOG_FATAL("misc", "Item slot {}", item->GetSlot());
- ABORT();
- }
-
- if (m_objectUpdated)
- {
- TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in update list!!", GetGUID().ToString());
- ABORT();
- }
-}
-
-void Object::_Create(ObjectGuid const& guid)
-{
- m_objectUpdated = false;
- m_guid = guid;
-}
+Object::~Object() = default;
void Object::AddToWorld()
{
- if (m_inWorld)
- return;
-
- m_inWorld = true;
-
- // synchronize values mirror with values array (changes will send in updatecreate opcode any way
- ASSERT(!m_objectUpdated);
- ClearUpdateMask(false);
+ BaseEntity::AddToWorld();
// Set new ref when adding to world (except if we already have one - also set in constructor to allow scripts to work in initialization phase)
// Changing the ref when adding/removing from world prevents accessing players on different maps (possibly from another thread)
@@ -122,109 +83,11 @@ void Object::AddToWorld()
void Object::RemoveFromWorld()
{
- if (!m_inWorld)
- return;
-
- m_inWorld = false;
-
- // if we remove from world then sending changes not required
- ClearUpdateMask(true);
+ BaseEntity::RemoveFromWorld();
m_scriptRef = nullptr;
}
-void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
-{
- if (!target)
- return;
-
- uint8 updateType = m_isNewObject ? UPDATETYPE_CREATE_OBJECT2 : UPDATETYPE_CREATE_OBJECT;
- uint8 objectType = m_objectTypeId;
- CreateObjectBits flags = m_updateFlag;
-
- if (target == this) // building packet for yourself
- {
- flags.ThisIsYou = true;
- flags.ActivePlayer = true;
- objectType = TYPEID_ACTIVE_PLAYER;
- }
-
- if (IsWorldObject())
- {
- WorldObject const* worldObject = static_cast<WorldObject const*>(this);
- if (!flags.MovementUpdate && !worldObject->m_movementInfo.transport.guid.IsEmpty())
- flags.MovementTransport = true;
-
- if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId())
- flags.AnimKit = true;
-
- if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
- flags.SmoothPhasing = true;
- }
-
- if (Unit const* unit = ToUnit())
- {
- flags.PlayHoverAnim = unit->IsPlayingHoverAnim();
-
- if (unit->GetVictim())
- flags.CombatVictim = true;
- }
-
- ByteBuffer& buf = data->GetBuffer();
- buf << uint8(updateType);
- buf << GetGUID();
- buf << uint8(objectType);
-
- BuildMovementUpdate(&buf, flags, target);
-
- UF::UpdateFieldFlag fieldFlags = GetUpdateFieldFlagsFor(target);
- std::size_t sizePos = buf.wpos();
- buf << uint32(0);
- buf << uint8(fieldFlags);
- BuildEntityFragments(&buf, m_entityFragments.GetIds());
- buf << uint8(1); // IndirectFragmentActive: CGObject
- BuildValuesCreate(&buf, fieldFlags, target);
- buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
-
- data->AddUpdateBlock();
-}
-
-void Object::SendUpdateToPlayer(Player* player)
-{
- // send create update to player
- UpdateData upd(player->GetMapId());
- WorldPacket packet;
-
- if (player->HaveAtClient(this))
- BuildValuesUpdateBlockForPlayer(&upd, player);
- else
- BuildCreateUpdateBlockForPlayer(&upd, player);
- upd.BuildPacket(&packet);
- player->SendDirectMessage(&packet);
-}
-
-void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const
-{
- ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
-
- EnumFlag<UF::UpdateFieldFlag> fieldFlags = GetUpdateFieldFlagsFor(target);
- std::size_t sizePos = buf.wpos();
- buf << uint32(0);
- buf << uint8(fieldFlags.HasFlag(UF::UpdateFieldFlag::Owner));
- buf << uint8(m_entityFragments.IdsChanged);
- if (m_entityFragments.IdsChanged)
- {
- buf << uint8(WowCS::EntityFragmentSerializationType::Full);
- BuildEntityFragments(&buf, m_entityFragments.GetIds());
- }
- buf << uint8(m_entityFragments.ContentsChangedMask);
-
- BuildValuesUpdate(&buf, fieldFlags, target);
- buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
-
- data->AddUpdateBlock();
-}
-
void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::UpdateFieldFlag flags, Player const* target) const
{
ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
@@ -238,486 +101,21 @@ void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::Updat
data->AddUpdateBlock();
}
-void Object::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
-{
- data->append(fragments.data(), fragments.size());
- *data << uint8(WowCS::EntityFragment::End);
-}
-
void Object::BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags) const
{
- uint8 contentsChangedMask = WowCS::CGObjectChangedMask;
- for (WowCS::EntityFragment updateableFragmentId : m_entityFragments.GetUpdateableIds())
- if (WowCS::IsIndirectFragment(updateableFragmentId))
- contentsChangedMask |= m_entityFragments.GetUpdateMaskFor(updateableFragmentId) >> 1; // set the "fragment exists" bit
-
- *data << uint8(flags.HasFlag(UF::UpdateFieldFlag::Owner));
- *data << uint8(false); // m_entityFragments.IdsChanged
- *data << uint8(contentsChangedMask);
-}
-
-void Object::BuildDestroyUpdateBlock(UpdateData* data) const
-{
- data->AddDestroyObject(GetGUID());
-}
-
-void Object::BuildOutOfRangeUpdateBlock(UpdateData* data) const
-{
- data->AddOutOfRangeGUID(GetGUID());
-}
-
-ByteBuffer& Object::PrepareValuesUpdateBuffer(UpdateData* data) const
-{
- ByteBuffer& buffer = data->GetBuffer();
- buffer << uint8(UPDATETYPE_VALUES);
- buffer << GetGUID();
- return buffer;
-}
-
-void Object::DestroyForPlayer(Player* target) const
-{
- ASSERT(target);
-
- UpdateData updateData(target->GetMapId());
- BuildDestroyUpdateBlock(&updateData);
- WorldPacket packet;
- updateData.BuildPacket(&packet);
- target->SendDirectMessage(&packet);
-}
-
-void Object::SendOutOfRangeForPlayer(Player* target) const
-{
- ASSERT(target);
-
- UpdateData updateData(target->GetMapId());
- BuildOutOfRangeUpdateBlock(&updateData);
- WorldPacket packet;
- updateData.BuildPacket(&packet);
- target->SendDirectMessage(&packet);
-}
-
-void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const
-{
- std::vector<uint32> const* PauseTimes = nullptr;
- if (GameObject const* go = ToGameObject())
- PauseTimes = go->GetPauseTimes();
-
- data->WriteBit(IsWorldObject()); // HasPositionFragment
- data->WriteBit(flags.NoBirthAnim);
- data->WriteBit(flags.EnablePortals);
- data->WriteBit(flags.PlayHoverAnim);
- data->WriteBit(flags.ThisIsYou);
- data->WriteBit(flags.MovementUpdate);
- data->WriteBit(flags.MovementTransport);
- data->WriteBit(flags.Stationary);
- data->WriteBit(flags.CombatVictim);
- data->WriteBit(flags.ServerTime);
- data->WriteBit(flags.Vehicle);
- data->WriteBit(flags.AnimKit);
- data->WriteBit(flags.Rotation);
- data->WriteBit(flags.GameObject);
- data->WriteBit(flags.SmoothPhasing);
- data->WriteBit(flags.SceneObject);
- data->WriteBit(flags.ActivePlayer);
- data->WriteBit(flags.Conversation);
- data->WriteBit(flags.Room);
- data->WriteBit(flags.Decor);
- data->WriteBit(flags.MeshObject);
- data->FlushBits();
-
- if (flags.MovementUpdate)
- {
- Unit const* unit = static_cast<Unit const*>(this);
- bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
- bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
- bool HasSpline = unit->IsSplineEnabled();
- bool HasInertia = unit->m_movementInfo.inertia.has_value();
- bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value();
- bool HasDriveStatus = unit->m_movementInfo.driveStatus.has_value();
- bool HasStandingOnGameObjectGUID = unit->m_movementInfo.standingOnGameObjectGUID.has_value();
-
- *data << GetGUID(); // MoverGUID
-
- *data << uint32(unit->GetUnitMovementFlags());
- *data << uint32(unit->GetExtraUnitMovementFlags());
- *data << uint32(unit->GetExtraUnitMovementFlags2());
-
- *data << uint32(unit->m_movementInfo.time); // MoveTime
- *data << float(unit->GetPositionX());
- *data << float(unit->GetPositionY());
- *data << float(unit->GetPositionZ());
- *data << float(unit->GetOrientation());
-
- *data << float(unit->m_movementInfo.pitch); // Pitch
- *data << float(unit->m_movementInfo.stepUpStartElevation); // StepUpStartElevation
-
- *data << uint32(0); // RemoveForcesIDs.size()
- *data << uint32(0); // MoveIndex
-
- //for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
- // *data << ObjectGuid(RemoveForcesIDs);
-
- data->WriteBit(HasStandingOnGameObjectGUID); // HasStandingOnGameObjectGUID
- data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
- data->WriteBit(HasFall); // HasFall
- data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
- data->WriteBit(false); // HeightChangeFailed
- data->WriteBit(false); // RemoteTimeValid
- data->WriteBit(HasInertia); // HasInertia
- data->WriteBit(HasAdvFlying); // HasAdvFlying
- data->WriteBit(HasDriveStatus); // HasDriveStatus
- data->FlushBits();
-
- if (!unit->m_movementInfo.transport.guid.IsEmpty())
- *data << unit->m_movementInfo.transport;
-
- if (HasStandingOnGameObjectGUID)
- *data << *unit->m_movementInfo.standingOnGameObjectGUID;
-
- if (HasInertia)
- {
- *data << unit->m_movementInfo.inertia->id;
- *data << unit->m_movementInfo.inertia->force.PositionXYZStream();
- *data << uint32(unit->m_movementInfo.inertia->lifetime);
- }
-
- if (HasAdvFlying)
- {
- *data << float(unit->m_movementInfo.advFlying->forwardVelocity);
- *data << float(unit->m_movementInfo.advFlying->upVelocity);
- }
-
- if (HasFall)
- {
- *data << uint32(unit->m_movementInfo.jump.fallTime); // Time
- *data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
-
- if (data->WriteBit(HasFallDirection))
- {
- *data << float(unit->m_movementInfo.jump.sinAngle); // Direction
- *data << float(unit->m_movementInfo.jump.cosAngle);
- *data << float(unit->m_movementInfo.jump.xyspeed); // Speed
- }
- }
-
- if (HasDriveStatus)
- {
- *data << float(unit->m_movementInfo.driveStatus->speed);
- *data << float(unit->m_movementInfo.driveStatus->movementAngle);
- data->WriteBit(unit->m_movementInfo.driveStatus->accelerating);
- data->WriteBit(unit->m_movementInfo.driveStatus->drifting);
- data->FlushBits();
- }
-
- *data << float(unit->GetSpeed(MOVE_WALK));
- *data << float(unit->GetSpeed(MOVE_RUN));
- *data << float(unit->GetSpeed(MOVE_RUN_BACK));
- *data << float(unit->GetSpeed(MOVE_SWIM));
- *data << float(unit->GetSpeed(MOVE_SWIM_BACK));
- *data << float(unit->GetSpeed(MOVE_FLIGHT));
- *data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
- *data << float(unit->GetSpeed(MOVE_TURN_RATE));
- *data << float(unit->GetSpeed(MOVE_PITCH_RATE));
-
- if (MovementForces const* movementForces = unit->GetMovementForces())
- {
- *data << uint32(movementForces->GetForces()->size());
- *data << float(movementForces->GetModMagnitude()); // MovementForcesModMagnitude
- }
- else
- {
- *data << uint32(0);
- *data << float(1.0f); // MovementForcesModMagnitude
- }
-
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_AIR_FRICTION));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_MAX_VEL));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LIFT_COEFFICIENT));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_DOUBLE_JUMP_VEL_MOD));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_GLIDE_START_MIN_HEIGHT));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_ADD_IMPULSE_MAX_SPEED));
- *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_BANKING_RATE));
- *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_BANKING_RATE));
- *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_DOWN));
- *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_DOWN));
- *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_UP));
- *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_UP));
- *data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
- *data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_SURFACE_FRICTION));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_OVER_MAX_DECELERATION));
- *data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LAUNCH_SPEED_COEFFICIENT));
-
- data->WriteBit(HasSpline);
- data->FlushBits();
-
- if (MovementForces const* movementForces = unit->GetMovementForces())
- for (MovementForce const& force : *movementForces->GetForces())
- WorldPackets::Movement::CommonMovement::WriteMovementForceWithDirection(force, *data, unit);
-
- if (HasSpline)
- WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
- }
-
- *data << uint32(PauseTimes ? PauseTimes->size() : 0);
-
- if (flags.Stationary)
- {
- WorldObject const* self = static_cast<WorldObject const*>(this);
- *data << self->GetStationaryPosition().PositionXYZOStream();
- }
-
- if (flags.CombatVictim)
+ uint8 contentsChangedMask = 0;
+ for (std::size_t i = 0; i < m_entityFragments.UpdateableCount; ++i)
{
- Unit const* unit = static_cast<Unit const*>(this);
- *data << unit->GetVictim()->GetGUID(); // CombatVictim
- }
+ if (WowCS::IsIndirectFragment(m_entityFragments.Updateable.Ids[i]))
+ contentsChangedMask |= m_entityFragments.Updateable.Masks[i] >> 1; // set the "fragment exists" bit
- if (flags.ServerTime)
- *data << uint32(GameTime::GetGameTimeMS());
-
- if (flags.Vehicle)
- {
- Unit const* unit = static_cast<Unit const*>(this);
- *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
- *data << float(unit->GetOrientation()); // InitialRawFacing
- }
-
- if (flags.AnimKit)
- {
- WorldObject const* self = static_cast<WorldObject const*>(this);
- *data << uint16(self->GetAIAnimKitId()); // AiID
- *data << uint16(self->GetMovementAnimKitId()); // MovementID
- *data << uint16(self->GetMeleeAnimKitId()); // MeleeID
- }
-
- if (flags.Rotation)
- {
- GameObject const* gameObject = static_cast<GameObject const*>(this);
- *data << uint64(gameObject->GetPackedLocalRotation()); // Rotation
+ if (m_entityFragments.Updateable.Ids[i] == WowCS::EntityFragment::CGObject)
+ contentsChangedMask |= m_entityFragments.Updateable.Masks[i];
}
- //if (flags.Room)
- // *data << ObjectGuid(HouseGUID);
-
- //if (flags.Decor)
- // *data << ObjectGuid(RoomGUID);
-
- //if (flags.MeshObject)
- //{
- // *data << ObjectGuid(AttachParentGUID);
- // *data << TaggedPosition<Position::XYZ>(PositionLocalSpace);
- // *data << QuaternionData(RotationLocalSpace);
- // *data << float(ScaleLocalSpace);
- // *data << uint8(AttachmentFlags);
- //}
-
- if (PauseTimes && !PauseTimes->empty())
- data->append(PauseTimes->data(), PauseTimes->size());
-
- if (flags.MovementTransport)
- {
- WorldObject const* self = static_cast<WorldObject const*>(this);
- *data << self->m_movementInfo.transport;
- }
-
- if (flags.GameObject)
- {
- GameObject const* gameObject = static_cast<GameObject const*>(this);
- Transport const* transport = gameObject->ToTransport();
-
- bool bit8 = false;
-
- *data << uint32(gameObject->GetWorldEffectID());
-
- data->WriteBit(bit8);
- data->WriteBit(transport != nullptr);
- data->WriteBit(gameObject->GetPathProgressForClient().has_value());
- data->FlushBits();
- if (transport)
- {
- uint32 period = transport->GetTransportPeriod();
-
- *data << uint32((((int64(transport->GetTimer()) - int64(GameTime::GetGameTimeMS())) % period) + period) % period); // TimeOffset
- *data << uint32(transport->GetNextStopTimestamp().value_or(0));
- data->WriteBit(transport->GetNextStopTimestamp().has_value());
- data->WriteBit(transport->IsStopped());
- data->WriteBit(false);
- data->FlushBits();
- }
-
- if (bit8)
- *data << uint32(0);
-
- if (gameObject->GetPathProgressForClient())
- *data << float(*gameObject->GetPathProgressForClient());
- }
-
- if (flags.SmoothPhasing)
- {
- SmoothPhasingInfo const* smoothPhasingInfo = static_cast<WorldObject const*>(this)->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID());
- ASSERT(smoothPhasingInfo);
-
- data->WriteBit(smoothPhasingInfo->ReplaceActive);
- data->WriteBit(smoothPhasingInfo->StopAnimKits);
- data->WriteBit(smoothPhasingInfo->ReplaceObject.has_value());
- data->FlushBits();
- if (smoothPhasingInfo->ReplaceObject)
- *data << *smoothPhasingInfo->ReplaceObject;
- }
-
- if (flags.SceneObject)
- {
- data->WriteBit(false); // HasLocalScriptData
- data->WriteBit(false); // HasPetBattleFullUpdate
- data->FlushBits();
-
- // if (HasLocalScriptData)
- // {
- // data->WriteBits(Data.length(), 7);
- // data->FlushBits();
- // data->WriteString(Data);
- // }
-
- // if (HasPetBattleFullUpdate)
- // {
- // for (std::size_t i = 0; i < 2; ++i)
- // {
- // *data << ObjectGuid(Players[i].CharacterID);
- // *data << int32(Players[i].TrapAbilityID);
- // *data << int32(Players[i].TrapStatus);
- // *data << uint16(Players[i].RoundTimeSecs);
- // *data << int8(Players[i].FrontPet);
- // *data << uint8(Players[i].InputFlags);
-
- // data->WriteBits(Players[i].Pets.size(), 2);
- // data->FlushBits();
- // for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
- // {
- // *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
- // *data << int32(Players[i].Pets[j].SpeciesID);
- // *data << int32(Players[i].Pets[j].CreatureID);
- // *data << int32(Players[i].Pets[j].DisplayID);
- // *data << int16(Players[i].Pets[j].Level);
- // *data << int16(Players[i].Pets[j].Xp);
- // *data << int32(Players[i].Pets[j].CurHealth);
- // *data << int32(Players[i].Pets[j].MaxHealth);
- // *data << int32(Players[i].Pets[j].Power);
- // *data << int32(Players[i].Pets[j].Speed);
- // *data << int32(Players[i].Pets[j].NpcTeamMemberID);
- // *data << uint8(Players[i].Pets[j].BreedQuality);
- // *data << uint16(Players[i].Pets[j].StatusFlags);
- // *data << int8(Players[i].Pets[j].Slot);
-
- // *data << uint32(Players[i].Pets[j].Abilities.size());
- // *data << uint32(Players[i].Pets[j].Auras.size());
- // *data << uint32(Players[i].Pets[j].States.size());
- // for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
- // {
- // *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
- // *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
- // *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
- // *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
- // *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
- // }
-
- // for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
- // {
- // *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
- // *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
- // *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
- // *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
- // *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
- // }
-
- // for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
- // {
- // *data << uint32(Players[i].Pets[j].States[k].StateID);
- // *data << int32(Players[i].Pets[j].States[k].StateValue);
- // }
-
- // data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
- // data->FlushBits();
- // data->WriteString(Players[i].Pets[j].CustomName);
- // }
- // }
-
- // for (std::size_t i = 0; i < 3; ++i)
- // {
- // *data << uint32(Enviros[j].Auras.size());
- // *data << uint32(Enviros[j].States.size());
- // for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
- // {
- // *data << int32(Enviros[j].Auras[j].AbilityID);
- // *data << uint32(Enviros[j].Auras[j].InstanceID);
- // *data << int32(Enviros[j].Auras[j].RoundsRemaining);
- // *data << int32(Enviros[j].Auras[j].CurrentRound);
- // *data << uint8(Enviros[j].Auras[j].CasterPBOID);
- // }
-
- // for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
- // {
- // *data << uint32(Enviros[i].States[j].StateID);
- // *data << int32(Enviros[i].States[j].StateValue);
- // }
- // }
-
- // *data << uint16(WaitingForFrontPetsMaxSecs);
- // *data << uint16(PvpMaxRoundTime);
- // *data << int32(CurRound);
- // *data << uint32(NpcCreatureID);
- // *data << uint32(NpcDisplayID);
- // *data << int8(CurPetBattleState);
- // *data << uint8(ForfeitPenalty);
- // *data << ObjectGuid(InitialWildPetGUID);
- // data->WriteBit(IsPVP);
- // data->WriteBit(CanAwardXP);
- // data->FlushBits();
- // }
- }
-
- if (flags.ActivePlayer)
- {
- Player const* player = static_cast<Player const*>(this);
-
- bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty();
- bool HasRuneState = player->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
-
- data->WriteBit(HasSceneInstanceIDs);
- data->WriteBit(HasRuneState);
- data->FlushBits();
- if (HasSceneInstanceIDs)
- {
- *data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size());
- for (auto const& [sceneInstanceId, _] : player->GetSceneMgr().GetSceneTemplateByInstanceMap())
- *data << uint32(sceneInstanceId);
- }
- if (HasRuneState)
- {
- float baseCd = float(player->GetRuneBaseCooldown());
- uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
-
- *data << uint8((1 << maxRunes) - 1);
- *data << uint8(player->GetRunesState());
- *data << uint32(maxRunes);
- for (uint32 i = 0; i < maxRunes; ++i)
- *data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
- }
- }
-
- if (flags.Conversation)
- {
- Conversation const* self = static_cast<Conversation const*>(this);
- if (data->WriteBit(self->GetTextureKitId() != 0))
- *data << uint32(self->GetTextureKitId());
-
- data->FlushBits();
- }
-}
-
-UF::UpdateFieldFlag Object::GetUpdateFieldFlagsFor(Player const* /*target*/) const
-{
- return UF::UpdateFieldFlag::None;
+ *data << uint8(flags.HasFlag(UF::UpdateFieldFlag::Owner));
+ *data << uint8(false); // m_entityFragments.IdsChanged
+ *data << uint8(contentsChangedMask);
}
void Object::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag /*flags*/, Player const* /*target*/) const
@@ -725,36 +123,32 @@ void Object::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag /*f
*data << uint32(0);
}
-void Object::AddToObjectUpdateIfNeeded()
+void Object::ClearUpdateMask(bool remove)
{
- if (m_inWorld && !m_objectUpdated)
- m_objectUpdated = AddToObjectUpdate();
+ m_values.ClearChangesMask(&Object::m_objectData);
+ BaseEntity::ClearUpdateMask(remove);
}
-void Object::ClearUpdateMask(bool remove)
+void Object::BuildObjectFragmentCreate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
{
- m_values.ClearChangesMask(&Object::m_objectData);
- m_entityFragments.IdsChanged = false;
+ static_cast<Object const*>(entity)->BuildValuesCreate(&data, flags, target);
+}
- if (m_objectUpdated)
- {
- if (remove)
- RemoveFromObjectUpdate();
- m_objectUpdated = false;
- }
+void Object::BuildObjectFragmentUpdate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
+{
+ static_cast<Object const*>(entity)->BuildValuesUpdate(&data, flags, target);
}
-void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
+bool Object::IsObjectFragmentChanged(BaseEntity const* entity)
{
- UpdateDataMapType::iterator iter = data_map.try_emplace(player, player->GetMapId()).first;
- BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
+ return entity->m_values.GetChangedObjectTypeMask() != 0;
}
std::string Object::GetDebugInfo() const
{
std::stringstream sstr;
- sstr << GetGUID().ToString() + " Entry " << GetEntry();
- return sstr.str();
+ sstr << BaseEntity::GetDebugInfo() << " Entry " << GetEntry();
+ return std::move(sstr).str();
}
void MovementInfo::OutDebug()
@@ -814,6 +208,8 @@ m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isStored
m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_liquidStatus(LIQUID_MAP_NO_WATER),
m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), _heartbeatTimer(HEARTBEAT_INTERVAL)
{
+ m_updateFlag.HasEntityPosition = true;
+
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
}
@@ -3721,6 +3117,8 @@ struct WorldObjectChangeAccumulator
void WorldObject::BuildUpdate(UpdateDataMapType& data_map)
{
+ BuildUpdateChangesMask();
+
WorldObjectChangeAccumulator notifier(*this, data_map);
WorldObjectVisibleChangeVisitor visitor(notifier);
//we must build packets for all visible players
@@ -3747,6 +3145,12 @@ ObjectGuid WorldObject::GetTransGUID() const
return ObjectGuid::Empty;
}
+void WorldObject::SetTransport(TransportBase* t)
+{
+ m_transport = t;
+ m_updateFlag.MovementTransport = !m_updateFlag.MovementUpdate && t != nullptr;
+}
+
float WorldObject::GetFloorZ() const
{
if (!IsInWorld())
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 5a6782dcddb..f5cdd6185e4 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -18,6 +18,7 @@
#ifndef _OBJECT_H
#define _OBJECT_H
+#include "BaseEntity.h"
#include "Common.h"
#include "Duration.h"
#include "Errors.h"
@@ -26,17 +27,13 @@
#include "ModelIgnoreFlags.h"
#include "MovementInfo.h"
#include "ObjectDefines.h"
-#include "ObjectGuid.h"
#include "Optional.h"
#include "PhaseShift.h"
#include "Position.h"
#include "SharedDefines.h"
#include "SpellDefines.h"
#include "UniqueTrackablePtr.h"
-#include "UpdateFields.h"
-#include "WowCSEntityDefinitions.h"
#include <list>
-#include <unordered_map>
class AreaTrigger;
class Conversation;
@@ -78,132 +75,17 @@ namespace WorldPackets
}
}
-typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
-
-struct CreateObjectBits
-{
- bool NoBirthAnim : 1;
- bool EnablePortals : 1;
- bool PlayHoverAnim : 1;
- bool MovementUpdate : 1;
- bool MovementTransport : 1;
- bool Stationary : 1;
- bool CombatVictim : 1;
- bool ServerTime : 1;
- bool Vehicle : 1;
- bool AnimKit : 1;
- bool Rotation : 1;
- bool GameObject : 1;
- bool SmoothPhasing : 1;
- bool ThisIsYou : 1;
- bool SceneObject : 1;
- bool ActivePlayer : 1;
- bool Conversation : 1;
- bool Room : 1;
- bool Decor : 1;
- bool MeshObject : 1;
-
- void Clear()
- {
- memset(this, 0, sizeof(CreateObjectBits));
- }
-};
-
-namespace UF
-{
- class UpdateFieldHolder
- {
- public:
- template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
- inline MutableFieldReference<T, false> ModifyValue(UpdateField<T, BlockBit, Bit>(Derived::* field));
-
- template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
- inline OptionalUpdateFieldSetter<T> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
-
- template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
- inline MutableFieldReference<T, false> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field), uint32 /*dummy*/);
-
- template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
- inline void ClearChangesMask(UpdateField<T, BlockBit, Bit>(Derived::* field));
-
- template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
- inline void ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
-
- uint32 GetChangedObjectTypeMask() const { return _changesMask; }
-
- bool HasChanged(uint32 index) const { return (_changesMask & UpdateMaskHelpers::GetBlockFlag(index)) != 0; }
-
- inline Object* GetOwner();
-
- private:
- friend Object;
-
- // This class is tightly tied to Object::m_values member, do not construct elsewhere
- UpdateFieldHolder() : _changesMask(0) { }
-
- uint32 _changesMask;
- };
-
- template<typename T>
- inline bool SetUpdateFieldValue(UpdateFieldPrivateSetter<T>& setter, typename UpdateFieldPrivateSetter<T>::value_type&& value)
- {
- return setter.SetValue(std::move(value));
- }
-
- template<typename T>
- inline typename DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter)
- {
- return setter.AddValue();
- }
-
- template<typename T>
- inline typename DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
- {
- return setter.InsertValue(index);
- }
-
- template<typename T>
- inline void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
- {
- setter.RemoveValue(index);
- }
-
- template<typename T>
- inline void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter<T>& setter)
- {
- setter.Clear();
- }
-
- template<typename K, typename V>
- inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
- {
- setter.RemoveKey(key);
- }
-
- template<typename T>
- inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
- {
- setter.RemoveValue();
- }
-}
-
float const DEFAULT_COLLISION_HEIGHT = 2.03128f; // Most common value in dbc
static constexpr Milliseconds const HEARTBEAT_INTERVAL = 5s + 200ms;
-class TC_GAME_API Object
+class TC_GAME_API Object : public BaseEntity
{
- ObjectGuid m_guid;
-
public:
virtual ~Object();
- bool IsInWorld() const { return m_inWorld; }
-
- virtual void AddToWorld();
- virtual void RemoveFromWorld();
+ void AddToWorld() override;
+ void RemoveFromWorld() override;
- static ObjectGuid GetGUID(Object const* o) { return o ? o->GetGUID() : ObjectGuid::Empty; }
- ObjectGuid const& GetGUID() const { return m_guid; }
uint32 GetEntry() const { return m_objectData->EntryID; }
void SetEntry(uint32 entry) { SetUpdateFieldValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::EntryID), entry); }
@@ -216,110 +98,71 @@ class TC_GAME_API Object
void RemoveDynamicFlag(uint32 flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::DynamicFlags), flag); }
void ReplaceAllDynamicFlags(uint32 flag) { SetUpdateFieldValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::DynamicFlags), flag); }
- TypeID GetTypeId() const { return m_objectTypeId; }
- bool isType(TypeMask mask) const { return (ObjectTypeMask[m_objectTypeId] & mask) != 0; }
-
- virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
- void SendUpdateToPlayer(Player* player);
-
- void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const;
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::UpdateFieldFlag flags, Player const* target) const;
- void BuildDestroyUpdateBlock(UpdateData* data) const;
- void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
- ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
-
- virtual void DestroyForPlayer(Player* target) const;
- void SendOutOfRangeForPlayer(Player* target) const;
- virtual void ClearUpdateMask(bool remove);
-
- virtual std::string GetNameForLocaleIdx(LocaleConstant locale) const = 0;
+ void ClearUpdateMask(bool remove) override;
virtual bool hasQuest(uint32 /* quest_id */) const { return false; }
virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; }
- void SetIsNewObject(bool enable) { m_isNewObject = enable; }
- bool IsDestroyedObject() const { return m_isDestroyedObject; }
- void SetDestroyedObject(bool destroyed) { m_isDestroyedObject = destroyed; }
- virtual void BuildUpdate(UpdateDataMapType&) { }
- void BuildFieldsUpdate(Player*, UpdateDataMapType &) const;
- inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); }
static WorldObject* ToWorldObject(Object* o) { return o ? o->ToWorldObject() : nullptr; }
static WorldObject const* ToWorldObject(Object const* o) { return o ? o->ToWorldObject() : nullptr; }
WorldObject* ToWorldObject() { if (IsWorldObject()) return reinterpret_cast<WorldObject*>(this); else return nullptr; }
WorldObject const* ToWorldObject() const { if (IsWorldObject()) return reinterpret_cast<WorldObject const*>(this); else return nullptr; }
- inline bool IsItem() const { return isType(TYPEMASK_ITEM); }
static Item* ToItem(Object* o) { return o ? o->ToItem() : nullptr; }
static Item const* ToItem(Object const* o) { return o ? o->ToItem() : nullptr; }
Item* ToItem() { if (IsItem()) return reinterpret_cast<Item*>(this); else return nullptr; }
Item const* ToItem() const { if (IsItem()) return reinterpret_cast<Item const*>(this); else return nullptr; }
- inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; }
static Player* ToPlayer(Object* o) { return o ? o->ToPlayer() : nullptr; }
static Player const* ToPlayer(Object const* o) { return o ? o->ToPlayer() : nullptr; }
Player* ToPlayer() { if (IsPlayer()) return reinterpret_cast<Player*>(this); else return nullptr; }
Player const* ToPlayer() const { if (IsPlayer()) return reinterpret_cast<Player const*>(this); else return nullptr; }
- inline bool IsCreature() const { return GetTypeId() == TYPEID_UNIT; }
static Creature* ToCreature(Object* o) { return o ? o->ToCreature() : nullptr; }
static Creature const* ToCreature(Object const* o) { return o ? o->ToCreature() : nullptr; }
Creature* ToCreature() { if (IsCreature()) return reinterpret_cast<Creature*>(this); else return nullptr; }
Creature const* ToCreature() const { if (IsCreature()) return reinterpret_cast<Creature const*>(this); else return nullptr; }
- inline bool IsUnit() const { return isType(TYPEMASK_UNIT); }
static Unit* ToUnit(Object* o) { return o ? o->ToUnit() : nullptr; }
static Unit const* ToUnit(Object const* o) { return o ? o->ToUnit() : nullptr; }
Unit* ToUnit() { if (IsUnit()) return reinterpret_cast<Unit*>(this); else return nullptr; }
Unit const* ToUnit() const { if (IsUnit()) return reinterpret_cast<Unit const*>(this); else return nullptr; }
- inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; }
static GameObject* ToGameObject(Object* o) { return o ? o->ToGameObject() : nullptr; }
static GameObject const* ToGameObject(Object const* o) { return o ? o->ToGameObject() : nullptr; }
GameObject* ToGameObject() { if (IsGameObject()) return reinterpret_cast<GameObject*>(this); else return nullptr; }
GameObject const* ToGameObject() const { if (IsGameObject()) return reinterpret_cast<GameObject const*>(this); else return nullptr; }
- inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; }
static Corpse* ToCorpse(Object* o) { return o ? o->ToCorpse() : nullptr; }
static Corpse const* ToCorpse(Object const* o) { return o ? o->ToCorpse() : nullptr; }
Corpse* ToCorpse() { if (IsCorpse()) return reinterpret_cast<Corpse*>(this); else return nullptr; }
Corpse const* ToCorpse() const { if (IsCorpse()) return reinterpret_cast<Corpse const*>(this); else return nullptr; }
- inline bool IsDynObject() const { return GetTypeId() == TYPEID_DYNAMICOBJECT; }
static DynamicObject* ToDynObject(Object* o) { return o ? o->ToDynObject() : nullptr; }
static DynamicObject const* ToDynObject(Object const* o) { return o ? o->ToDynObject() : nullptr; }
DynamicObject* ToDynObject() { if (IsDynObject()) return reinterpret_cast<DynamicObject*>(this); else return nullptr; }
DynamicObject const* ToDynObject() const { if (IsDynObject()) return reinterpret_cast<DynamicObject const*>(this); else return nullptr; }
- inline bool IsAreaTrigger() const { return GetTypeId() == TYPEID_AREATRIGGER; }
static AreaTrigger* ToAreaTrigger(Object* o) { return o ? o->ToAreaTrigger() : nullptr; }
static AreaTrigger const* ToAreaTrigger(Object const* o) { return o ? o->ToAreaTrigger() : nullptr; }
AreaTrigger* ToAreaTrigger() { if (IsAreaTrigger()) return reinterpret_cast<AreaTrigger*>(this); else return nullptr; }
AreaTrigger const* ToAreaTrigger() const { if (IsAreaTrigger()) return reinterpret_cast<AreaTrigger const*>(this); else return nullptr; }
- inline bool IsSceneObject() const { return GetTypeId() == TYPEID_SCENEOBJECT; }
static SceneObject* ToSceneObject(Object* o) { return o ? o->ToSceneObject() : nullptr; }
static SceneObject const* ToSceneObject(Object const* o) { return o ? o->ToSceneObject() : nullptr; }
SceneObject* ToSceneObject() { if (IsSceneObject()) return reinterpret_cast<SceneObject*>(this); else return nullptr; }
SceneObject const* ToSceneObject() const { if (IsSceneObject()) return reinterpret_cast<SceneObject const*>(this); else return nullptr; }
- inline bool IsConversation() const { return GetTypeId() == TYPEID_CONVERSATION; }
static Conversation* ToConversation(Object* o) { return o ? o->ToConversation() : nullptr; }
static Conversation const* ToConversation(Object const* o) { return o ? o->ToConversation() : nullptr; }
Conversation* ToConversation() { if (IsConversation()) return reinterpret_cast<Conversation*>(this); else return nullptr; }
Conversation const* ToConversation() const { if (IsConversation()) return reinterpret_cast<Conversation const*>(this); else return nullptr; }
- friend UF::UpdateFieldHolder;
- UF::UpdateFieldHolder m_values;
UF::UpdateField<UF::ObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_OBJECT> m_objectData;
- template<typename T>
- void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter<T> const& /*setter*/)
- {
- AddToObjectUpdateIfNeeded();
- }
-
- virtual std::string GetDebugInfo() const;
+ std::string GetDebugInfo() const override;
Trinity::unique_weak_ptr<Object> GetWeakPtr() const { return m_scriptRef; }
@@ -330,242 +173,22 @@ class TC_GAME_API Object
protected:
Object();
- void _Create(ObjectGuid const& guid);
-
- template<typename T>
- void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
- {
- if (UF::SetUpdateFieldValue(setter, std::move(value)))
- AddToObjectUpdateIfNeeded();
- }
-
- template<typename T>
- void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
- {
- static_assert(std::is_integral<T>::value, "SetUpdateFieldFlagValue must be used with integral types");
- SetUpdateFieldValue(setter, setter.GetValue() | flag);
- }
-
- template<typename T>
- void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
- {
- static_assert(std::is_integral<T>::value, "RemoveUpdateFieldFlagValue must be used with integral types");
- SetUpdateFieldValue(setter, setter.GetValue() & ~flag);
- }
-
- template<typename T>
- typename UF::DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter)
- {
- AddToObjectUpdateIfNeeded();
- return UF::AddDynamicUpdateFieldValue(setter);
- }
-
- template<typename T>
- typename UF::DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
- {
- AddToObjectUpdateIfNeeded();
- return UF::InsertDynamicUpdateFieldValue(setter, index);
- }
-
- template<typename T>
- void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
- {
- AddToObjectUpdateIfNeeded();
- UF::RemoveDynamicUpdateFieldValue(setter, index);
- }
-
- template<typename K, typename V>
- void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
- {
- AddToObjectUpdateIfNeeded();
- UF::RemoveMapUpdateFieldValue(setter, key);
- }
-
- template<typename T>
- void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter<T> setter)
- {
- AddToObjectUpdateIfNeeded();
- UF::ClearDynamicUpdateFieldValues(setter);
- }
-
- template<typename T>
- void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter<T> setter)
- {
- AddToObjectUpdateIfNeeded();
- UF::RemoveOptionalUpdateFieldValue(setter);
- }
-
- // stat system helpers
- template<typename T>
- void SetUpdateFieldStatValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
- {
- static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
- SetUpdateFieldValue(setter, std::max(value, T(0)));
- }
-
- template<typename T>
- void ApplyModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type mod, bool apply)
- {
- static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
-
- T value = setter.GetValue();
- if (apply)
- value += mod;
- else
- value -= mod;
-
- SetUpdateFieldValue(setter, value);
- }
-
- template<typename T>
- void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, float percent, bool apply)
- {
- static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
-
- T value = setter.GetValue();
-
- // don't want to include Util.h here
- //ApplyPercentModFloatVar(value, percent, apply);
- if (percent == -100.0f)
- percent = -99.99f;
- value *= (apply ? (100.0f + percent) / 100.0f : 100.0f / (100.0f + percent));
-
- SetUpdateFieldValue(setter, value);
- }
-
- template<typename Action>
- void DoWithSuppressingObjectUpdates(Action&& action)
- {
- bool wasUpdatedBeforeAction = m_objectUpdated;
- action();
- if (m_objectUpdated && !wasUpdatedBeforeAction)
- {
- RemoveFromObjectUpdate();
- m_objectUpdated = false;
- }
- }
-
- void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const;
- virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const;
virtual void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const = 0;
virtual void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const = 0;
- static void BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments);
void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags) const;
public:
virtual void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const;
- protected:
- TypeID m_objectTypeId;
- CreateObjectBits m_updateFlag;
- WowCS::EntityFragmentsHolder m_entityFragments;
-
- virtual bool AddToObjectUpdate() = 0;
- virtual void RemoveFromObjectUpdate() = 0;
- void AddToObjectUpdateIfNeeded();
-
- bool m_objectUpdated;
-
private:
- bool m_inWorld;
- bool m_isNewObject;
- bool m_isDestroyedObject;
+ static void BuildObjectFragmentCreate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target);
+ static void BuildObjectFragmentUpdate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target);
+ static bool IsObjectFragmentChanged(BaseEntity const* entity);
struct NoopObjectDeleter { void operator()(Object*) const { /*noop - not managed*/ } };
Trinity::unique_trackable_ptr<Object> m_scriptRef;
-
- Object(Object const& right) = delete;
- Object(Object&& right) = delete;
- Object& operator=(Object const& right) = delete;
- Object& operator=(Object&& right) = delete;
};
-inline Object* UF::UpdateFieldHolder::GetOwner()
-{
-#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Winvalid-offsetof"
-#endif
-
- return reinterpret_cast<Object*>(reinterpret_cast<std::byte*>(this) - offsetof(Object, m_values));
-
-#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
-#pragma GCC diagnostic pop
-#endif
-}
-
-template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
-inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(UpdateField<T, BlockBit, Bit> Derived::* field)
-{
- Object* owner = GetOwner();
- owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
- _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
-
- return { (static_cast<Derived*>(owner)->*field)._value };
-}
-
-template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
-inline UF::OptionalUpdateFieldSetter<T> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
-{
- Object* owner = GetOwner();
- owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
- _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
-
- return { static_cast<Derived*>(owner)->*field };
-}
-
-template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
-inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field, uint32 /*dummy*/)
-{
- Object* owner = GetOwner();
- owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
- _changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
-
- auto& uf = (static_cast<Derived*>(owner)->*field);
- if (!uf.has_value())
- uf.ConstructValue();
-
- return { *uf._value };
-}
-
-template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
-inline void UF::UpdateFieldHolder::ClearChangesMask(UpdateField<T, BlockBit, Bit> Derived::* field)
-{
- Object* owner = GetOwner();
- owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
- {
- _changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
- if (!_changesMask)
- owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- }
- else
- owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
-
- (static_cast<Derived*>(owner)->*field)._value.ClearChangesMask();
-}
-
-template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
-inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
-{
- Object* owner = GetOwner();
- if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
- {
- _changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
- if (!_changesMask)
- owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
- }
- else
- owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
-
- auto& uf = (static_cast<Derived*>(owner)->*field);
- if (uf.has_value())
- uf._value->ClearChangesMask();
-}
-
template <class T_VALUES, class T_FLAGS, class FLAG_TYPE, size_t ARRAY_SIZE>
class FlaggedValuesArray32
{
@@ -921,7 +544,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
uint32 GetTransTime() const { return m_movementInfo.transport.time; }
int8 GetTransSeat() const { return m_movementInfo.transport.seat; }
virtual ObjectGuid GetTransGUID() const;
- void SetTransport(TransportBase* t) { m_transport = t; }
+ void SetTransport(TransportBase* t);
MovementInfo m_movementInfo;
diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h
index 98cf4c5632a..d24c228c872 100644
--- a/src/server/game/Entities/Object/ObjectGuid.h
+++ b/src/server/game/Entities/Object/ObjectGuid.h
@@ -78,10 +78,10 @@ enum TypeMask
TYPEMASK_LOOT_OBJECT = 1 << TYPEID_LOOT_OBJECT,
TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_PLAYER | TYPEMASK_DYNAMICOBJECT,
- TYPEMASK_WORLDOBJECT = TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE | TYPEMASK_AREATRIGGER | TYPEMASK_SCENEOBJECT | TYPEMASK_CONVERSATION
+ TYPEMASK_WORLDOBJECT = TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE | TYPEMASK_AREATRIGGER | TYPEMASK_SCENEOBJECT | TYPEMASK_CONVERSATION | TYPEMASK_MESH_OBJECT
};
-inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES> ObjectTypeMask =
+inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES + 1> ObjectTypeMask =
{
TYPEMASK_OBJECT,
TYPEMASK_OBJECT | TYPEMASK_ITEM,
@@ -101,6 +101,7 @@ inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES> ObjectTypeMask =
TYPEMASK_OBJECT | TYPEMASK_AI_GROUP,
TYPEMASK_OBJECT | TYPEMASK_SCENARIO,
TYPEMASK_OBJECT | TYPEMASK_LOOT_OBJECT,
+ 0,
};
enum class HighGuid
diff --git a/src/server/game/Entities/Object/SmoothPhasing.cpp b/src/server/game/Entities/Object/SmoothPhasing.cpp
index 4b5377eb043..a1b504a5b78 100644
--- a/src/server/game/Entities/Object/SmoothPhasing.cpp
+++ b/src/server/game/Entities/Object/SmoothPhasing.cpp
@@ -18,6 +18,13 @@
#include "SmoothPhasing.h"
#include "MapUtils.h"
+SmoothPhasing::SmoothPhasing() = default;
+SmoothPhasing::SmoothPhasing(SmoothPhasing const&) = default;
+SmoothPhasing::SmoothPhasing(SmoothPhasing&&) noexcept = default;
+SmoothPhasing& SmoothPhasing::operator=(SmoothPhasing const&) = default;
+SmoothPhasing& SmoothPhasing::operator=(SmoothPhasing&&) noexcept = default;
+SmoothPhasing::~SmoothPhasing() = default;
+
void SmoothPhasing::SetViewerDependentInfo(ObjectGuid seer, SmoothPhasingInfo const& info)
{
if (!std::holds_alternative<SmoothPhasingInfoViewerDependent>(_storage))
diff --git a/src/server/game/Entities/Object/SmoothPhasing.h b/src/server/game/Entities/Object/SmoothPhasing.h
index 6d211e8da28..520a6d97126 100644
--- a/src/server/game/Entities/Object/SmoothPhasing.h
+++ b/src/server/game/Entities/Object/SmoothPhasing.h
@@ -37,6 +37,13 @@ struct SmoothPhasingInfo
class TC_GAME_API SmoothPhasing
{
public:
+ SmoothPhasing();
+ SmoothPhasing(SmoothPhasing const&);
+ SmoothPhasing(SmoothPhasing&&) noexcept;
+ SmoothPhasing& operator=(SmoothPhasing const&);
+ SmoothPhasing& operator=(SmoothPhasing&&) noexcept;
+ ~SmoothPhasing();
+
void SetViewerDependentInfo(ObjectGuid seer, SmoothPhasingInfo const& info);
void ClearViewerDependentInfo(ObjectGuid seer);
diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp
index 34fe6d86f89..1b342102f9f 100644
--- a/src/server/game/Entities/Object/Updates/UpdateData.cpp
+++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp
@@ -18,18 +18,36 @@
#include "UpdateData.h"
#include "Errors.h"
#include "WorldPacket.h"
-#include "Opcodes.h"
+#include <utility>
UpdateData::UpdateData(uint32 map) : m_map(map), m_blockCount(0) { }
-void UpdateData::AddDestroyObject(ObjectGuid guid)
+UpdateData::UpdateData(UpdateData&& right) noexcept :
+ m_map(right.m_map), m_blockCount(std::exchange(right.m_blockCount, 0)),
+ m_destroyGUIDs(std::move(right.m_destroyGUIDs)),
+ m_outOfRangeGUIDs(std::move(right.m_outOfRangeGUIDs)),
+ m_data(std::move(right.m_data))
{
- m_destroyGUIDs.insert(guid);
}
-void UpdateData::AddOutOfRangeGUID(GuidSet& guids)
+UpdateData& UpdateData::operator=(UpdateData&& right) noexcept
+{
+ if (this != &right)
+ {
+ m_map = right.m_map;
+ m_blockCount = std::exchange(right.m_blockCount, 0);
+ m_destroyGUIDs = std::move(right.m_destroyGUIDs);
+ m_outOfRangeGUIDs = std::move(right.m_outOfRangeGUIDs);
+ m_data = std::move(right.m_data);
+ }
+ return *this;
+}
+
+UpdateData::~UpdateData() = default;
+
+void UpdateData::AddDestroyObject(ObjectGuid guid)
{
- m_outOfRangeGUIDs.insert(guids.begin(), guids.end());
+ m_destroyGUIDs.insert(guid);
}
void UpdateData::AddOutOfRangeGUID(ObjectGuid guid)
diff --git a/src/server/game/Entities/Object/Updates/UpdateData.h b/src/server/game/Entities/Object/Updates/UpdateData.h
index 3dc50bde23d..48ad58659e5 100644
--- a/src/server/game/Entities/Object/Updates/UpdateData.h
+++ b/src/server/game/Entities/Object/Updates/UpdateData.h
@@ -15,13 +15,13 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __UPDATEDATA_H
-#define __UPDATEDATA_H
+#ifndef TRINITYCORE_UPDATE_DATA_H
+#define TRINITYCORE_UPDATE_DATA_H
-#include "Define.h"
#include "ByteBuffer.h"
+#include "Define.h"
+#include "FlatSet.h"
#include "ObjectGuid.h"
-#include <set>
class WorldPacket;
@@ -37,14 +37,11 @@ class UpdateData
{
public:
UpdateData(uint32 map);
- UpdateData(UpdateData&& right) noexcept : m_map(right.m_map), m_blockCount(right.m_blockCount),
- m_outOfRangeGUIDs(std::move(right.m_outOfRangeGUIDs)),
- m_data(std::move(right.m_data))
- {
- }
+ UpdateData(UpdateData&& right) noexcept;
+ UpdateData& operator=(UpdateData&& right) noexcept;
+ ~UpdateData();
void AddDestroyObject(ObjectGuid guid);
- void AddOutOfRangeGUID(GuidSet& guids);
void AddOutOfRangeGUID(ObjectGuid guid);
void AddUpdateBlock() { ++m_blockCount; }
ByteBuffer& GetBuffer() { return m_data; }
@@ -52,16 +49,15 @@ class UpdateData
bool HasData() const { return m_blockCount > 0 || !m_outOfRangeGUIDs.empty() || !m_destroyGUIDs.empty(); }
void Clear();
- GuidSet const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; }
-
protected:
uint32 m_map;
uint32 m_blockCount;
- GuidSet m_destroyGUIDs;
- GuidSet m_outOfRangeGUIDs;
+ Trinity::Containers::FlatSet<ObjectGuid> m_destroyGUIDs;
+ Trinity::Containers::FlatSet<ObjectGuid> m_outOfRangeGUIDs;
ByteBuffer m_data;
UpdateData(UpdateData const& right) = delete;
UpdateData& operator=(UpdateData const& right) = delete;
};
-#endif
+
+#endif // TRINITYCORE_UPDATE_DATA_H
diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp
index 7627a6a82ae..5f1e6013196 100644
--- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp
+++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp
@@ -8478,13 +8478,13 @@ void ConversationData::ClearChangesMask()
_changesMask.ResetAll();
}
-void AaBox::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void AaBox::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << Low;
data << High;
}
-void AaBox::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void AaBox::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data << Low;
data << High;
@@ -8588,7 +8588,7 @@ void VendorData::ClearChangesMask()
_changesMask.ResetAll();
}
-void DecorStoragePersistedDataDyes::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void DecorStoragePersistedDataDyes::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
for (uint32 i = 0; i < 3; ++i)
{
@@ -8596,7 +8596,7 @@ void DecorStoragePersistedDataDyes::WriteCreate(ByteBuffer& data, Object const*
}
}
-void DecorStoragePersistedDataDyes::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void DecorStoragePersistedDataDyes::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
for (uint32 i = 0; i < 3; ++i)
{
@@ -8606,10 +8606,10 @@ void DecorStoragePersistedDataDyes::WriteUpdate(ByteBuffer& data, bool ignoreCha
bool DecorStoragePersistedDataDyes::operator==(DecorStoragePersistedDataDyes const& right) const
{
- return std::ranges::equal(DyeColorID, right.DyeColorID);
+ return DyeColorID == right.DyeColorID;
}
-void DecorStoragePersistedData::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void DecorStoragePersistedData::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << *HouseGUID;
data << uint8(Field_20);
@@ -8621,7 +8621,7 @@ void DecorStoragePersistedData::WriteCreate(ByteBuffer& data, Object const* owne
}
}
-void DecorStoragePersistedData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void DecorStoragePersistedData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
Mask changesMask = _changesMask;
if (ignoreChangesMask)
@@ -8721,7 +8721,7 @@ void HousingDecorData::ClearChangesMask()
_changesMask.ResetAll();
}
-void HousingDoorData::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void HousingDoorData::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << int32(RoomComponentID);
data << *RoomComponentOffset;
@@ -8729,7 +8729,7 @@ void HousingDoorData::WriteCreate(ByteBuffer& data, Object const* owner, Player
data << *AttachedRoomGUID;
}
-void HousingDoorData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void HousingDoorData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
Mask changesMask = _changesMask;
if (ignoreChangesMask)
@@ -8768,7 +8768,7 @@ void HousingDoorData::ClearChangesMask()
_changesMask.ResetAll();
}
-void HousingRoomData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingRoomData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
data << *HouseGUID;
data << int32(HouseRoomID);
@@ -8786,12 +8786,12 @@ void HousingRoomData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi
}
}
-void HousingRoomData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingRoomData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteUpdate(data, _changesMask, false, owner, receiver);
}
-void HousingRoomData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const
+void HousingRoomData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(changesMask.GetBlock(0), 7);
@@ -8943,7 +8943,7 @@ void HousingRoomComponentMeshData::ClearChangesMask()
_changesMask.ResetAll();
}
-void HousingPlayerHouseData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingPlayerHouseData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
data << *BnetAccount;
data << int32(PlotIndex);
@@ -8956,12 +8956,12 @@ void HousingPlayerHouseData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldF
data << *EntityGUID;
}
-void HousingPlayerHouseData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingPlayerHouseData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteUpdate(data, _changesMask, false, owner, receiver);
}
-void HousingPlayerHouseData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const
+void HousingPlayerHouseData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(changesMask.GetBlock(0), 10);
@@ -9105,13 +9105,13 @@ void HousingPlotAreaTriggerData::ClearChangesMask()
_changesMask.ResetAll();
}
-void PlayerHouseInfo::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void PlayerHouseInfo::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << HouseGUID;
data << OwnerGUID;
}
-void PlayerHouseInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void PlayerHouseInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data << HouseGUID;
data << OwnerGUID;
@@ -9123,13 +9123,13 @@ bool PlayerHouseInfo::operator==(PlayerHouseInfo const& right) const
&& OwnerGUID == right.OwnerGUID;
}
-void HousingOwner::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void HousingOwner::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << BnetAccountGUID;
data << PlayerGUID;
}
-void HousingOwner::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void HousingOwner::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data << BnetAccountGUID;
data << PlayerGUID;
@@ -9141,7 +9141,7 @@ bool HousingOwner::operator==(HousingOwner const& right) const
&& PlayerGUID == right.PlayerGUID;
}
-void NeighborhoodMirrorData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void NeighborhoodMirrorData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(Name->size() + 1, 8);
data << *OwnerGUID;
@@ -9158,12 +9158,12 @@ void NeighborhoodMirrorData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldF
}
}
-void NeighborhoodMirrorData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void NeighborhoodMirrorData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteUpdate(data, _changesMask, false, owner, receiver);
}
-void NeighborhoodMirrorData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const
+void NeighborhoodMirrorData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(changesMask.GetBlock(0), 5);
@@ -9235,7 +9235,7 @@ void NeighborhoodMirrorData::ClearChangesMask()
_changesMask.ResetAll();
}
-void MirroredMeshObjectData::WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const
+void MirroredMeshObjectData::WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const
{
data << *AttachParentGUID;
data << *PositionLocalSpace;
@@ -9247,7 +9247,7 @@ void MirroredMeshObjectData::WriteCreate(ByteBuffer& data, Object const* owner,
data << uint8(AttachmentFlags);
}
-void MirroredMeshObjectData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const
+void MirroredMeshObjectData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const
{
Mask changesMask = _changesMask;
if (ignoreChangesMask)
@@ -9294,17 +9294,17 @@ void MirroredMeshObjectData::ClearChangesMask()
_changesMask.ResetAll();
}
-void MirroredPositionData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void MirroredPositionData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
PositionData->WriteCreate(data, owner, receiver);
}
-void MirroredPositionData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void MirroredPositionData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteUpdate(data, _changesMask, false, owner, receiver);
}
-void MirroredPositionData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const
+void MirroredPositionData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(changesMask.GetBlock(0), 2);
@@ -9590,18 +9590,18 @@ void PlayerHouseInfoComponentData::ClearChangesMask()
_changesMask.ResetAll();
}
-void HousingStorageData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingStorageData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteMapFieldCreate(Decor, data, owner, receiver);
data << uint32(DecorMaxOwnedCount);
}
-void HousingStorageData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const
+void HousingStorageData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const
{
WriteUpdate(data, _changesMask, false, owner, receiver);
}
-void HousingStorageData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const
+void HousingStorageData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const
{
data.WriteBits(changesMask.GetBlock(0), 3);
diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h
index 582473c702c..95976b87218 100644
--- a/src/server/game/Entities/Object/Updates/UpdateFields.h
+++ b/src/server/game/Entities/Object/Updates/UpdateFields.h
@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef UpdateFields_h__
-#define UpdateFields_h__
+#ifndef TRINITYCORE_UPDATE_FIELDS_H
+#define TRINITYCORE_UPDATE_FIELDS_H
#include "EnumFlag.h"
#include "ItemPacketsCommon.h"
@@ -34,6 +34,7 @@ class AreaTrigger;
class AzeriteEmpoweredItem;
class AzeriteItem;
class Bag;
+class BaseEntity;
class ByteBuffer;
class Conversation;
class Corpse;
@@ -1610,8 +1611,8 @@ struct AaBox : public IsUpdateFieldStructureTag
TaggedPosition<Position::XYZ> Low;
TaggedPosition<Position::XYZ> High;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
bool operator==(AaBox const& right) const;
bool operator!=(AaBox const& right) const { return !(*this == right); }
};
@@ -1641,10 +1642,10 @@ struct VendorData : public IsUpdateFieldStructureTag, public HasChangesMask<2>
struct DecorStoragePersistedDataDyes : public IsUpdateFieldStructureTag
{
- int32 DyeColorID[3];
+ std::array<int32, 3> DyeColorID;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
bool operator==(DecorStoragePersistedDataDyes const& right) const;
bool operator!=(DecorStoragePersistedDataDyes const& right) const { return !(*this == right); }
};
@@ -1655,8 +1656,8 @@ struct DecorStoragePersistedData : public IsUpdateFieldStructureTag, public HasC
OptionalUpdateField<UF::DecorStoragePersistedDataDyes, -1, 1> Dyes;
UpdateField<uint8, -1, 2> Field_20;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1681,8 +1682,8 @@ struct HousingDoorData : public IsUpdateFieldStructureTag, public HasChangesMask
UpdateField<uint8, 0, 3> RoomComponentType;
UpdateField<ObjectGuid, 0, 4> AttachedRoomGUID;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1695,9 +1696,9 @@ struct HousingRoomData : public IsUpdateFieldStructureTag, public HasChangesMask
UpdateField<int32, 0, 5> Flags;
UpdateField<int32, 0, 6> FloorIndex;
- void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1731,9 +1732,9 @@ struct HousingPlayerHouseData : public IsUpdateFieldStructureTag, public HasChan
UpdateField<uint32, 0, 8> RoomPlacementBudget;
UpdateField<ObjectGuid, 0, 9> EntityGUID;
- void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1766,8 +1767,8 @@ struct PlayerHouseInfo : public IsUpdateFieldStructureTag
ObjectGuid HouseGUID;
ObjectGuid OwnerGUID;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
bool operator==(PlayerHouseInfo const& right) const;
bool operator!=(PlayerHouseInfo const& right) const { return !(*this == right); }
};
@@ -1777,8 +1778,8 @@ struct HousingOwner : public IsUpdateFieldStructureTag
ObjectGuid BnetAccountGUID;
ObjectGuid PlayerGUID;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
bool operator==(HousingOwner const& right) const;
bool operator!=(HousingOwner const& right) const { return !(*this == right); }
};
@@ -1790,9 +1791,9 @@ struct NeighborhoodMirrorData : public IsUpdateFieldStructureTag, public HasChan
UpdateField<ObjectGuid, 0, 4> OwnerGUID;
UpdateField<std::string, 0, 3> Name;
- void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1804,8 +1805,8 @@ struct MirroredMeshObjectData : public IsUpdateFieldStructureTag, public HasChan
UpdateField<float, 0, 4> ScaleLocalSpace;
UpdateField<uint8, 0, 5> AttachmentFlags;
- void WriteCreate(ByteBuffer& data, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1813,9 +1814,9 @@ struct MirroredPositionData : public IsUpdateFieldStructureTag, public HasChange
{
UpdateField<UF::MirroredMeshObjectData, 0, 1> PositionData;
- void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1880,9 +1881,9 @@ struct HousingStorageData : public IsUpdateFieldStructureTag, public HasChangesM
MapUpdateField<ObjectGuid, UF::DecorStoragePersistedData, 0, 1> Decor;
UpdateField<uint32, 0, 2> DecorMaxOwnedCount;
- void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Object const* owner, Player const* receiver) const;
- void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Object const* owner, Player const* receiver) const;
+ void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, BaseEntity const* owner, Player const* receiver) const;
+ void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, BaseEntity const* owner, Player const* receiver) const;
void ClearChangesMask();
};
@@ -1907,4 +1908,4 @@ struct HousingFixtureData : public IsUpdateFieldStructureTag, public HasChangesM
}
-#endif // UpdateFields_h__
+#endif // TRINITYCORE_UPDATE_FIELDS_H
diff --git a/src/server/game/Entities/Object/Updates/UpdateMask.h b/src/server/game/Entities/Object/Updates/UpdateMask.h
index 3071632d603..0e3fd9f32ae 100644
--- a/src/server/game/Entities/Object/Updates/UpdateMask.h
+++ b/src/server/game/Entities/Object/Updates/UpdateMask.h
@@ -19,7 +19,6 @@
#define UpdateMask_h__
#include "Define.h"
-#include <algorithm>
#include <cstring> // std::memset
namespace UpdateMaskHelpers
@@ -68,10 +67,11 @@ public:
constexpr bool IsAnySet() const
{
- return std::ranges::any_of(_blocksMask, [](uint32 blockMask)
- {
- return blockMask != 0;
- });
+ for (uint32 i = 0; i < BlocksMaskCount; ++i)
+ if (_blocksMask[i])
+ return true;
+
+ return false;
}
constexpr void Reset(uint32 index)
diff --git a/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.cpp b/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.cpp
index b89d7aab275..b80541d547d 100644
--- a/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.cpp
+++ b/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.cpp
@@ -21,7 +21,8 @@
namespace WowCS
{
-void EntityFragmentsHolder::Add(EntityFragment fragment, bool update)
+void EntityFragmentsHolder::Add(EntityFragment fragment, bool update,
+ EntityFragmentSerializeFn serializeCreate, EntityFragmentSerializeFn serializeUpdate, EntityFragmentIsChangedFn isChanged)
{
ASSERT(Count < Ids.size());
@@ -43,23 +44,34 @@ void EntityFragmentsHolder::Add(EntityFragment fragment, bool update)
if (IsUpdateableFragment(fragment))
{
- ASSERT(UpdateableCount < UpdateableIds.size());
+ ASSERT(UpdateableCount < Updateable.Ids.size());
+ ASSERT(serializeCreate && serializeUpdate && isChanged);
- auto insertedItr = insertSorted(UpdateableIds, UpdateableCount, fragment).first;
- std::ptrdiff_t index = std::ranges::distance(UpdateableIds.begin(), insertedItr);
+ auto insertedItr = insertSorted(Updateable.Ids, UpdateableCount, fragment).first;
+ std::ptrdiff_t index = std::ranges::distance(Updateable.Ids.begin(), insertedItr);
uint8 maskLowPart = ContentsChangedMask & ((1 << index) - 1);
uint8 maskHighPart = (ContentsChangedMask & ~((1 << index) - 1)) << (1 + IsIndirectFragment(fragment));
ContentsChangedMask = maskLowPart | maskHighPart;
for (uint8 i = 0, maskIndex = 0; i < UpdateableCount; ++i)
{
- UpdateableMasks[i] = 1 << maskIndex++;
- if (IsIndirectFragment(UpdateableIds[i]))
+ Updateable.Masks[i] = 1 << maskIndex++;
+ if (IsIndirectFragment(Updateable.Ids[i]))
{
- ContentsChangedMask |= UpdateableMasks[i]; // set the first bit to true to activate fragment
+ ContentsChangedMask |= Updateable.Masks[i]; // set the first bit to true to activate fragment
++maskIndex;
- UpdateableMasks[i] <<= 1;
+ Updateable.Masks[i] <<= 1;
}
}
+
+ auto insertAtIndex = []<typename T, size_t N>(std::array<T, N>& arr, uint8 size, std::ptrdiff_t i, T value)
+ {
+ std::ranges::move_backward(arr.begin() + i, arr.begin() + size - 1, arr.begin() + size);
+ arr[i] = value;
+ };
+
+ insertAtIndex(Updateable.SerializeCreate, UpdateableCount, index, serializeCreate);
+ insertAtIndex(Updateable.SerializeUpdate, UpdateableCount, index, serializeUpdate);
+ insertAtIndex(Updateable.IsChanged, UpdateableCount, index, isChanged);
}
if (update)
@@ -86,22 +98,32 @@ void EntityFragmentsHolder::Remove(EntityFragment fragment)
if (IsUpdateableFragment(fragment))
{
- auto [removedItr, removed] = removeSorted(UpdateableIds, UpdateableCount, fragment);
+ auto [removedItr, removed] = removeSorted(Updateable.Ids, UpdateableCount, fragment);
if (removed)
{
- std::ptrdiff_t index = std::ranges::distance(UpdateableIds.begin(), removedItr);
+ std::ptrdiff_t index = std::ranges::distance(Updateable.Ids.begin(), removedItr);
uint8 maskLowPart = ContentsChangedMask & ((1 << index) - 1);
uint8 maskHighPart = (ContentsChangedMask & ~((1 << index) - 1)) >> (1 + IsIndirectFragment(fragment));
ContentsChangedMask = maskLowPart | maskHighPart;
for (uint8 i = 0, maskIndex = 0; i < UpdateableCount; ++i)
{
- UpdateableMasks[i] = 1 << maskIndex++;
- if (IsIndirectFragment(UpdateableIds[i]))
+ Updateable.Masks[i] = 1 << maskIndex++;
+ if (IsIndirectFragment(Updateable.Ids[i]))
{
++maskIndex;
- UpdateableMasks[i] <<= 1;
+ Updateable.Masks[i] <<= 1;
}
}
+
+ auto removeAtIndex = []<typename T, size_t N>(std::array<T, N>& arr, uint8 oldSize, std::ptrdiff_t i, std::type_identity_t<T> value)
+ {
+ *std::ranges::move(arr.begin() + i + 1, arr.begin() + oldSize, arr.begin() + i).out = value;
+ };
+
+ uint8 oldSize = UpdateableCount + 1;
+ removeAtIndex(Updateable.SerializeCreate, oldSize, index, nullptr);
+ removeAtIndex(Updateable.SerializeUpdate, oldSize, index, nullptr);
+ removeAtIndex(Updateable.IsChanged, oldSize, index, nullptr);
}
}
diff --git a/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.h b/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.h
index f3d8182ff83..d8e501e20ba 100644
--- a/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.h
+++ b/src/server/game/Entities/Object/Updates/WowCSEntityDefinitions.h
@@ -22,6 +22,15 @@
#include <array>
#include <span>
+class BaseEntity;
+class ByteBuffer;
+class Player;
+
+namespace UF
+{
+enum class UpdateFieldFlag : uint8;
+}
+
namespace WowCS
{
enum class EntityFragment : uint8
@@ -99,10 +108,35 @@ inline constexpr bool IsIndirectFragment(EntityFragment frag)
|| frag == EntityFragment::PlayerHouseInfoComponent_C;
}
-// common case optimization, make use of the fact that fragment arrays are sorted
-inline constexpr uint8 CGObjectActiveMask = 0x1;
-inline constexpr uint8 CGObjectChangedMask = 0x2;
-inline constexpr uint8 CGObjectUpdateMask = CGObjectActiveMask | CGObjectChangedMask;
+template <auto /*FragmentMemberPtr*/>
+struct FragmentSerializationTraits
+{
+};
+
+template <typename Entity, typename Fragment, Fragment Entity::* FragmentData>
+struct FragmentSerializationTraits<FragmentData>
+{
+ static void BuildCreate(BaseEntity const* baseEntity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
+ {
+ Entity const* entity = static_cast<Entity const*>(baseEntity);
+ (entity->*FragmentData)->WriteCreate(data, flags, entity, target);
+ }
+
+ static void BuildUpdate(BaseEntity const* baseEntity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
+ {
+ Entity const* entity = static_cast<Entity const*>(baseEntity);
+ (entity->*FragmentData)->WriteUpdate(data, flags, entity, target);
+ }
+
+ static bool IsChanged(BaseEntity const* baseEntity)
+ {
+ Entity const* entity = static_cast<Entity const*>(baseEntity);
+ return (entity->*FragmentData)->GetChangesMask().IsAnySet();
+ }
+};
+
+using EntityFragmentSerializeFn = void (*)(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target);
+using EntityFragmentIsChangedFn = bool (*)(BaseEntity const* entity);
struct EntityFragmentsHolder
{
@@ -111,34 +145,42 @@ struct EntityFragmentsHolder
EntityFragment::End, EntityFragment::End, EntityFragment::End, EntityFragment::End,
EntityFragment::End, EntityFragment::End, EntityFragment::End, EntityFragment::End
};
- uint8 Count = 0;
- bool IdsChanged = false;
- std::array<EntityFragment, 4> UpdateableIds =
+ template <std::size_t N>
+ struct UpdateableFragments
{
- EntityFragment::End, EntityFragment::End, EntityFragment::End, EntityFragment::End
+ std::array<EntityFragment, N> Ids =
+ {
+ EntityFragment::End, EntityFragment::End, EntityFragment::End, EntityFragment::End
+ };
+ std::array<uint8, N> Masks = { };
+ std::array<EntityFragmentSerializeFn, N> SerializeCreate = { };
+ std::array<EntityFragmentSerializeFn, N> SerializeUpdate = { };
+ std::array<EntityFragmentIsChangedFn, N> IsChanged = { };
};
- std::array<uint8, 4> UpdateableMasks = { };
+
+ UpdateableFragments<4> Updateable;
+
+ uint8 Count = 0;
+ bool IdsChanged = false;
+
uint8 UpdateableCount = 0;
uint8 ContentsChangedMask = 0;
- void Add(EntityFragment fragment, bool update);
- void Remove(EntityFragment fragment);
+ void Add(EntityFragment fragment, bool update,
+ EntityFragmentSerializeFn serializeCreate, EntityFragmentSerializeFn serializeUpdate, EntityFragmentIsChangedFn isChanged);
- std::span<EntityFragment const> GetIds() const { return std::span(Ids.begin(), Count); }
- std::span<EntityFragment const> GetUpdateableIds() const { return std::span(UpdateableIds.begin(), UpdateableCount); }
+ inline void Add(EntityFragment fragment, bool update) { Add(fragment, update, nullptr, nullptr, nullptr); }
- uint8 GetUpdateMaskFor(EntityFragment fragment) const
+ template <typename SerializationTraits>
+ inline void Add(EntityFragment fragment, bool update, SerializationTraits)
{
- if (fragment == EntityFragment::CGObject) // common case optimization, make use of the fact that fragment arrays are sorted
- return CGObjectChangedMask;
+ Add(fragment, update, &SerializationTraits::BuildCreate, &SerializationTraits::BuildUpdate, &SerializationTraits::IsChanged);
+ }
- for (uint8 i = 1; i < UpdateableCount; ++i)
- if (UpdateableIds[i] == fragment)
- return UpdateableMasks[i];
+ void Remove(EntityFragment fragment);
- return 0;
- }
+ std::span<EntityFragment const> GetIds() const { return std::span(Ids.begin(), Count); }
};
enum class EntityFragmentSerializationType : uint8
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 949743f16ae..669fcb36287 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -1683,7 +1683,7 @@ bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry, uint32 /*p
SetMap(map);
// TODO: counter should be constructed as (summon_count << 32) | petNumber
- Object::_Create(ObjectGuid::Create<HighGuid::Pet>(map->GetId(), Entry, guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Pet>(map->GetId(), Entry, guidlow));
m_spawnId = guidlow;
m_originalEntry = Entry;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ecddafd9c28..4eb409c8b12 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -17,6 +17,7 @@
#include "Player.h"
#include "AreaTrigger.h"
+#include "Account.h"
#include "AccountMgr.h"
#include "AchievementMgr.h"
#include "ArenaTeam.h"
@@ -387,7 +388,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
//FIXME: outfitId not used in player creating
/// @todo need more checks against packet modifications
- Object::_Create(ObjectGuid::Create<HighGuid::Player>(guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Player>(guidlow));
m_name = createInfo->Name;
@@ -1540,6 +1541,8 @@ void Player::AddToWorld()
for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
if (m_items[i])
m_items[i]->AddToWorld();
+
+ GetSession()->GetBattlenetAccount().AddToWorld();
}
void Player::RemoveFromWorld()
@@ -1559,6 +1562,8 @@ void Player::RemoveFromWorld()
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
}
+ GetSession()->GetBattlenetAccount().RemoveFromWorld();
+
// Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate
for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
if (m_items[i])
@@ -3592,6 +3597,8 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
for (Item* item : m_items)
if (item)
item->BuildCreateUpdateBlockForPlayer(data, target);
+
+ GetSession()->GetBattlenetAccount().BuildCreateUpdateBlockForPlayer(data, target);
}
Unit::BuildCreateUpdateBlockForPlayer(data, target);
@@ -3706,7 +3713,7 @@ void Player::ValuesUpdateForPlayerWithMaskSender::operator()(Player const* playe
player->SendDirectMessage(&packet);
}
-void Player::DestroyForPlayer(Player* target) const
+void Player::DestroyForPlayer(Player const* target) const
{
Unit::DestroyForPlayer(target);
@@ -17856,7 +17863,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
return false;
}
- Object::_Create(guid);
+ _Create(guid);
m_name = std::move(fields.name);
@@ -24097,7 +24104,7 @@ uint8 Player::GetStartLevel(uint8 race, uint8 playerClass, Optional<int32> chara
return startLevel;
}
-bool Player::HaveAtClient(Object const* u) const
+bool Player::HaveAtClient(BaseEntity const* u) const
{
return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end();
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 62b5e410559..ead0c144f7f 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2233,7 +2233,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void operator()(Player const* player) const;
};
- void DestroyForPlayer(Player* target) const override;
+ void DestroyForPlayer(Player const* target) const override;
// notifiers
void SendAttackSwingCancelAttack() const;
@@ -2631,7 +2631,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
GuidUnorderedSet m_clientGUIDs;
GuidUnorderedSet m_visibleTransports;
- bool HaveAtClient(Object const* u) const;
+ bool HaveAtClient(BaseEntity const* u) const;
bool IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects = false) const override;
diff --git a/src/server/game/Entities/SceneObject/SceneObject.cpp b/src/server/game/Entities/SceneObject/SceneObject.cpp
index 46875c51b06..3d8a7bca451 100644
--- a/src/server/game/Entities/SceneObject/SceneObject.cpp
+++ b/src/server/game/Entities/SceneObject/SceneObject.cpp
@@ -117,7 +117,7 @@ bool SceneObject::Create(ObjectGuid::LowType lowGuid, SceneType type, uint32 sce
SetPrivateObjectOwner(privateObjectOwner);
- Object::_Create(ObjectGuid::Create<HighGuid::SceneObject>(GetMapId(), sceneId, lowGuid));
+ _Create(ObjectGuid::Create<HighGuid::SceneObject>(GetMapId(), sceneId, lowGuid));
PhasingHandler::InheritPhaseShift(this, creator);
UpdatePositionData();
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index f7ac68ef840..81733d625fd 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -107,7 +107,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float
return false;
}
- Object::_Create(ObjectGuid::Create<HighGuid::Transport>(guidlow));
+ _Create(ObjectGuid::Create<HighGuid::Transport>(guidlow));
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
if (!goinfo)
@@ -689,6 +689,8 @@ void Transport::UpdatePassengerPositions(PassengerSet const& passengers)
void Transport::BuildUpdate(UpdateDataMapType& data_map)
{
+ BuildUpdateChangesMask();
+
for (MapReference const& playerReference : GetMap()->GetPlayers())
if (playerReference.GetSource()->InSamePhase(this))
BuildFieldsUpdate(playerReference.GetSource(), data_map);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index cb39caa6db4..f51da1de0f8 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -313,7 +313,7 @@ Unit::Unit(bool isWorldObject) :
m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
i_motionMaster(std::make_unique<MotionMaster>(this)), m_regenTimer(0), m_vehicle(nullptr),
m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
- m_threatManager(this), m_aiLocked(false), _playHoverAnim(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
+ m_threatManager(this), m_aiLocked(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
_spellHistory(std::make_unique<SpellHistory>(this))
{
m_objectTypeId = TYPEID_UNIT;
@@ -5902,6 +5902,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
m_attacking = victim;
m_attacking->_addAttacker(this);
+ m_updateFlag.CombatVictim = true;
// Set our target
SetTarget(victim->GetGUID());
@@ -5952,6 +5953,7 @@ bool Unit::AttackStop()
Unit* victim = m_attacking;
+ m_updateFlag.CombatVictim = false;
m_attacking->_removeAttacker(this);
m_attacking = nullptr;
@@ -11201,6 +11203,7 @@ void Unit::SetAIAnimKitId(uint16 animKitId)
return;
_aiAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetAIAnimKit data;
data.Unit = GetGUID();
@@ -11217,6 +11220,7 @@ void Unit::SetMovementAnimKitId(uint16 animKitId)
return;
_movementAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetMovementAnimKit data;
data.Unit = GetGUID();
@@ -11233,6 +11237,7 @@ void Unit::SetMeleeAnimKitId(uint16 animKitId)
return;
_meleeAnimKitId = animKitId;
+ m_updateFlag.AnimKit = _aiAnimKitId != 0 || _movementAnimKitId != 0 || _meleeAnimKitId != 0;
WorldPackets::Misc::SetMeleeAnimKit data;
data.Unit = GetGUID();
@@ -14074,7 +14079,7 @@ void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
if (IsPlayingHoverAnim() == enable)
return;
- _playHoverAnim = enable;
+ m_updateFlag.PlayHoverAnim = enable;
if (!sendUpdate)
return;
@@ -14123,7 +14128,7 @@ UF::UpdateFieldFlag Unit::GetUpdateFieldFlagsFor(Player const* target) const
return flags;
}
-void Unit::DestroyForPlayer(Player* target) const
+void Unit::DestroyForPlayer(Player const* target) const
{
if (Battleground* bg = target->GetBattleground())
{
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 10e719d343a..ed291549b04 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1138,7 +1138,7 @@ class TC_GAME_API Unit : public WorldObject
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false);
- bool IsPlayingHoverAnim() const { return _playHoverAnim; }
+ bool IsPlayingHoverAnim() const { return m_updateFlag.PlayHoverAnim; }
void SetPlayHoverAnim(bool enable, bool sendUpdate = true);
void CalculateHoverHeight();
void SetHoverHeight(float hoverHeight) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::HoverHeight), hoverHeight); }
@@ -1878,7 +1878,7 @@ class TC_GAME_API Unit : public WorldObject
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const override;
- void DestroyForPlayer(Player* target) const override;
+ void DestroyForPlayer(Player const* target) const override;
void ClearUpdateMask(bool remove) override;
void _UpdateSpells(uint32 time);
@@ -2030,8 +2030,6 @@ class TC_GAME_API Unit : public WorldObject
uint32 _oldFactionId; ///< faction before charm
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
- bool _playHoverAnim;
-
uint16 _aiAnimKitId;
uint16 _movementAnimKitId;
uint16 _meleeAnimKitId;
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 232c5748d51..ca39f80ec34 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -34,6 +34,18 @@
#include "Unit.h"
#include <sstream>
+class VehicleJoinEvent : public BasicEvent
+{
+public:
+ VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) { }
+ bool Execute(uint64, uint32) override;
+ void Abort(uint64) override;
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator Seat;
+};
+
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry), _status(STATUS_NONE)
{
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index fb740a7d962..f494f0684b3 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -122,17 +122,4 @@ class TC_GAME_API Vehicle final : public TransportBase
PendingJoinEventContainer _pendingJoinEvents; ///< Collection of delayed join events for prospective passengers
};
-class TC_GAME_API VehicleJoinEvent : public BasicEvent
-{
- friend class Vehicle;
- protected:
- VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) { }
- bool Execute(uint64, uint32) override;
- void Abort(uint64) override;
-
- Vehicle* Target;
- Unit* Passenger;
- SeatMap::iterator Seat;
-};
-
#endif
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index c886f41ae44..0ea2ff54b80 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -1967,7 +1967,7 @@ void Map::SendObjectUpdates()
while (!_updateObjects.empty())
{
- Object* obj = *_updateObjects.begin();
+ BaseEntity* obj = *_updateObjects.begin();
ASSERT(obj->IsInWorld());
_updateObjects.erase(_updateObjects.begin());
obj->BuildUpdate(update_players);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index c3fcfeb1aa4..d78bb09700b 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -45,6 +45,7 @@
#include <set>
#include <unordered_set>
+class BaseEntity;
class Battleground;
class BattlegroundMap;
class BattlegroundScript;
@@ -567,12 +568,12 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
return GetGuidSequenceGenerator(high).GetNextAfterMaxUsed();
}
- void AddUpdateObject(Object* obj)
+ void AddUpdateObject(BaseEntity* obj)
{
_updateObjects.insert(obj);
}
- void RemoveUpdateObject(Object* obj)
+ void RemoveUpdateObject(BaseEntity* obj)
{
_updateObjects.erase(obj);
}
@@ -821,7 +822,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::unordered_map<ObjectGuid, Corpse*> _corpsesByPlayer;
std::unordered_set<Corpse*> _corpseBones;
- std::unordered_set<Object*> _updateObjects;
+ std::unordered_set<BaseEntity*> _updateObjects;
MPSCQueue<FarSpellCallback> _farSpellCallbacks;
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index d2b2b96a69b..a336b5790ad 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -15,11 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- \ingroup u2w
-*/
-
#include "WorldSession.h"
+#include "Account.h"
#include "AccountMgr.h"
#include "AuthenticationPackets.h"
#include "Bag.h"
@@ -107,17 +104,19 @@ bool WorldSessionFilter::Process(WorldPacket* packet)
}
/// WorldSession constructor
-WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time,
- std::string os, Minutes timezoneOffset, uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter):
+WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::string&& battlenetAccountEmail,
+ std::shared_ptr<WorldSocket>&& sock, AccountTypes sec, uint8 expansion, time_t mute_time, std::string&& os, Minutes timezoneOffset,
+ uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter) :
m_muteTime(mute_time),
m_timeOutTime(0),
AntiDOS(this),
m_GUIDLow(UI64LIT(0)),
_player(nullptr),
+ m_Socket({ std::move(sock), nullptr }),
_security(sec),
_accountId(id),
_accountName(std::move(name)),
- _battlenetAccountId(battlenetAccountId),
+ _battlenetAccount(new Battlenet::Account(this, ObjectGuid::Create<HighGuid::BNetAccount>(battlenetAccountId), std::move(battlenetAccountEmail))),
m_accountExpansion(expansion),
m_expansion(std::min<uint8>(expansion, sWorld->getIntConfig(CONFIG_EXPANSION))),
_os(std::move(os)),
@@ -151,14 +150,13 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun
_battlePetMgr(std::make_unique<BattlePets::BattlePetMgr>(this)),
_collectionMgr(std::make_unique<CollectionMgr>(this))
{
- if (sock)
+ if (m_Socket[CONNECTION_TYPE_REALM])
{
- m_Address = sock->GetRemoteIpAddress().to_string();
+ m_Address = m_Socket[CONNECTION_TYPE_REALM]->GetRemoteIpAddress().to_string();
ResetTimeOutTime(false);
LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = {};", GetAccountId()); // One-time query
}
- m_Socket[CONNECTION_TYPE_REALM] = std::move(sock);
_instanceConnectKey.Raw = UI64LIT(0);
}
@@ -195,6 +193,16 @@ bool WorldSession::PlayerDisconnected() const
m_Socket[CONNECTION_TYPE_INSTANCE] && m_Socket[CONNECTION_TYPE_INSTANCE]->IsOpen());
}
+uint32 WorldSession::GetBattlenetAccountId() const
+{
+ return GetBattlenetAccountGUID().GetCounter();
+}
+
+ObjectGuid WorldSession::GetBattlenetAccountGUID() const
+{
+ return _battlenetAccount->GetGUID();
+}
+
std::string const & WorldSession::GetPlayerName() const
{
return _player != nullptr ? _player->GetName() : DefaultPlayerName;
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 2c55b457ce7..9c5dee6a355 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -15,10 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/// \addtogroup u2w
-/// @{
-/// \file
-
#ifndef __WORLDSESSION_H
#define __WORLDSESSION_H
@@ -70,6 +66,11 @@ enum InventoryResult : uint8;
enum class StableResult : uint8;
enum class TabardVendorType : int32;
+namespace Battlenet
+{
+class Account;
+}
+
namespace BattlePets
{
class BattlePetMgr;
@@ -969,8 +970,9 @@ struct PacketCounter
class TC_GAME_API WorldSession
{
public:
- WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time,
- std::string os, Minutes timezoneOffset, uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter);
+ WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::string&& battlenetAccountEmail,
+ std::shared_ptr<WorldSocket>&& sock, AccountTypes sec, uint8 expansion, time_t mute_time, std::string&& os, Minutes timezoneOffset,
+ uint32 build, ClientBuild::VariantId clientBuildVariant, LocaleConstant locale, uint32 recruiter, bool isARecruiter);
~WorldSession();
bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); }
@@ -1006,8 +1008,9 @@ class TC_GAME_API WorldSession
uint32 GetAccountId() const { return _accountId; }
ObjectGuid GetAccountGUID() const { return ObjectGuid::Create<HighGuid::WowAccount>(GetAccountId()); }
std::string const& GetAccountName() const { return _accountName; }
- uint32 GetBattlenetAccountId() const { return _battlenetAccountId; }
- ObjectGuid GetBattlenetAccountGUID() const { return ObjectGuid::Create<HighGuid::BNetAccount>(GetBattlenetAccountId()); }
+ uint32 GetBattlenetAccountId() const;
+ ObjectGuid GetBattlenetAccountGUID() const;
+ Battlenet::Account& GetBattlenetAccount() const { return *_battlenetAccount; }
Player* GetPlayer() const { return _player; }
std::string const& GetPlayerName() const;
std::string GetPlayerInfo() const;
@@ -1964,14 +1967,14 @@ class TC_GAME_API WorldSession
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
Player* _player;
- std::shared_ptr<WorldSocket> m_Socket[MAX_CONNECTION_TYPES];
+ std::array<std::shared_ptr<WorldSocket>, MAX_CONNECTION_TYPES> m_Socket;
std::string m_Address; // Current Remote Address
// std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session!
AccountTypes _security;
uint32 _accountId;
std::string _accountName;
- uint32 _battlenetAccountId;
+ std::unique_ptr<Battlenet::Account> _battlenetAccount;
uint8 m_accountExpansion;
uint8 m_expansion;
std::string _os;
@@ -2028,4 +2031,3 @@ class TC_GAME_API WorldSession
};
#endif
-/// @}
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index a701939c313..3aa0064b34c 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -29,6 +29,7 @@
#include "IpBanCheckConnectionInitializer.h"
#include "PacketLog.h"
#include "ProtobufJSON.h"
+#include "QueryResultStructured.h"
#include "RealmList.h"
#include "RBAC.h"
#include "RealmList.pb.h"
@@ -616,6 +617,7 @@ struct AccountInfo
struct
{
uint32 Id;
+ std::string Email;
bool IsLockedToIP;
std::string LastIP;
std::string LockCountry;
@@ -633,39 +635,42 @@ struct AccountInfo
uint32 Recruiter;
std::string OS;
Minutes TimezoneOffset;
- bool IsRectuiter;
+ bool IsRecruiter;
AccountTypes Security;
bool IsBanned;
} Game;
bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; }
- explicit AccountInfo(Field const* fields)
+ explicit AccountInfo(PreparedResultSet const* result)
{
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
- // SELECT a.id, a.session_key, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel,
- // 14 15 16
- // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id
- // FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?)
- // LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter
- // WHERE a.username = ? AND LENGTH(a.session_key) = 40 ORDER BY aa.RealmID DESC LIMIT 1
- Game.Id = fields[0].GetUInt32();
- Game.KeyData = fields[1].GetBinary<64>();
- BattleNet.LastIP = fields[2].GetString();
- BattleNet.IsLockedToIP = fields[3].GetBool();
- BattleNet.LockCountry = fields[4].GetString();
- Game.Expansion = fields[5].GetUInt8();
- Game.MuteTime = fields[6].GetInt64();
- Game.Build = fields[7].GetUInt32();
- Game.Locale = LocaleConstant(fields[8].GetUInt8());
- Game.Recruiter = fields[9].GetUInt32();
- Game.OS = fields[10].GetString();
- Game.TimezoneOffset = Minutes(fields[11].GetInt16());
- BattleNet.Id = fields[12].GetUInt32();
- Game.Security = AccountTypes(fields[13].GetUInt8());
- BattleNet.IsBanned = fields[14].GetUInt32() != 0;
- Game.IsBanned = fields[15].GetUInt32() != 0;
- Game.IsRectuiter = fields[16].GetUInt32() != 0;
+ // SELECT a.id AS accountId, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id AS bnet_account_id, ba.email as bnet_account_email, aa.SecurityLevel,
+ // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate AS is_bnet_banned, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate AS is_banned, r.id AS recruitId
+ // FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id
+ // LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1
+ // WHERE a.username = ? AND LENGTH(a.session_key_bnet) = 64 ORDER BY aa.RealmID DESC LIMIT 1
+
+ DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (account_id)(session_key_bnet)(last_ip)(locked)(lock_country)(expansion)(mutetime)(client_build)
+ (locale)(recruiter)(os)(timezone_offset)(bnet_account_id)(bnet_account_email)(SecurityLevel)(is_bnet_banned)(is_banned)(recruitId)) fields { *result };
+
+ Game.Id = fields.account_id().GetUInt32();
+ Game.KeyData = fields.session_key_bnet().GetBinary<64>();
+ BattleNet.LastIP = fields.last_ip().GetStringView();
+ BattleNet.IsLockedToIP = fields.locked().GetBool();
+ BattleNet.LockCountry = fields.lock_country().GetStringView();
+ Game.Expansion = fields.expansion().GetUInt8();
+ Game.MuteTime = fields.mutetime().GetInt64();
+ Game.Build = fields.client_build().GetUInt32();
+ Game.Locale = LocaleConstant(fields.locale().GetUInt8());
+ Game.Recruiter = fields.recruiter().GetUInt32();
+ Game.OS = fields.os().GetStringView();
+ Game.TimezoneOffset = Minutes(fields.timezone_offset().GetInt16());
+ BattleNet.Id = fields.bnet_account_id().GetUInt32();
+ BattleNet.Email = fields.bnet_account_email().GetStringView();
+ Game.Security = AccountTypes(fields.SecurityLevel().GetUInt8());
+ BattleNet.IsBanned = fields.is_bnet_banned().GetUInt32() != 0;
+ Game.IsBanned = fields.is_banned().GetUInt32() != 0;
+ Game.IsRecruiter = fields.recruitId().GetUInt32() != 0;
if (Game.Locale >= TOTAL_LOCALES)
Game.Locale = LOCALE_enUS;
@@ -707,7 +712,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::
std::string address = GetRemoteIpAddress().to_string();
- AccountInfo account(result->Fetch());
+ AccountInfo account(result.get());
ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(account.Game.Build);
if (!buildInfo)
@@ -887,9 +892,9 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::
_authed = true;
_worldSession = new WorldSession(account.Game.Id, std::move(*joinTicket->mutable_gameaccount()), account.BattleNet.Id,
- static_pointer_cast<WorldSocket>(shared_from_this()), account.Game.Security, account.Game.Expansion, mutetime,
- account.Game.OS, account.Game.TimezoneOffset, account.Game.Build, buildVariant, account.Game.Locale,
- account.Game.Recruiter, account.Game.IsRectuiter);
+ std::move(account.BattleNet.Email), static_pointer_cast<WorldSocket>(shared_from_this()), account.Game.Security,
+ account.Game.Expansion, mutetime, std::move(account.Game.OS), account.Game.TimezoneOffset, account.Game.Build, buildVariant,
+ account.Game.Locale, account.Game.Recruiter, account.Game.IsRecruiter);
QueueQuery(_worldSession->LoadPermissionsAsync().WithPreparedCallback([this](PreparedQueryResult result)
{
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 149c063bf6a..bb5a8acf7c6 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1197,7 +1197,8 @@ void World::LoadConfigSettings(bool reload)
_gameRules =
{
- { .Rule = ::GameRule::TransmogEnabled, .Value = true }
+ { .Rule = ::GameRule::TransmogEnabled, .Value = true },
+ { .Rule = ::GameRule::HousingEnabled, .Value = true }
};
if (reload)