mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Objects: Refactor building SMSG_UPDATE_OBJECT to make CGObject fragment optional as well as making integrating additional entity fragments easier
This commit is contained in:
@@ -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());
|
||||
*data << uint32(m_values.GetChangedObjectTypeMask());
|
||||
|
||||
if (m_values.HasChanged(TYPEID_OBJECT))
|
||||
m_objectData->WriteUpdate(*data, flags, this, target);
|
||||
if (m_values.HasChanged(TYPEID_OBJECT))
|
||||
m_objectData->WriteUpdate(*data, flags, this, target);
|
||||
|
||||
if (m_values.HasChanged(TYPEID_UNIT))
|
||||
m_unitData->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
|
||||
|
||||
@@ -1786,6 +1786,8 @@ bool Item::IsBindedNotWith(Player const* player) const
|
||||
|
||||
void Item::BuildUpdate(UpdateDataMapType& data_map)
|
||||
{
|
||||
Object::BuildUpdateChangesMask();
|
||||
|
||||
if (Player* owner = GetOwner())
|
||||
BuildFieldsUpdate(owner, data_map);
|
||||
ClearUpdateMask(false);
|
||||
|
||||
@@ -103,8 +103,16 @@ void BaseEntity::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* targe
|
||||
buf << uint32(0);
|
||||
buf << uint8(fieldFlags);
|
||||
BuildEntityFragments(&buf, m_entityFragments.GetIds());
|
||||
buf << uint8(1); // IndirectFragmentActive: CGObject
|
||||
BuildValuesCreate(&buf, fieldFlags, target);
|
||||
|
||||
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();
|
||||
@@ -140,13 +148,20 @@ void BaseEntity::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const*
|
||||
}
|
||||
buf << uint8(m_entityFragments.ContentsChangedMask);
|
||||
|
||||
BuildValuesUpdate(&buf, fieldFlags, target);
|
||||
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();
|
||||
}
|
||||
|
||||
void BaseEntity::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
|
||||
inline void BaseEntity::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
|
||||
{
|
||||
data->append(fragments.data(), fragments.size());
|
||||
*data << uint8(WowCS::EntityFragment::End);
|
||||
@@ -635,6 +650,17 @@ void BaseEntity::ClearUpdateMask(bool remove)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -189,6 +189,7 @@ class TC_GAME_API BaseEntity
|
||||
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;
|
||||
@@ -322,8 +323,6 @@ class TC_GAME_API BaseEntity
|
||||
|
||||
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);
|
||||
|
||||
TypeID m_objectTypeId = static_cast<TypeID>(NUM_CLIENT_OBJECT_TYPES);
|
||||
@@ -365,7 +364,6 @@ 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();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
@@ -376,7 +374,6 @@ 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();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
@@ -387,7 +384,6 @@ 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();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
@@ -403,13 +399,7 @@ inline void UF::UpdateFieldHolder::ClearChangesMask(UpdateField<T, BlockBit, Bit
|
||||
{
|
||||
BaseEntity* 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));
|
||||
|
||||
(static_cast<Derived*>(owner)->*field)._value.ClearChangesMask();
|
||||
}
|
||||
@@ -419,13 +409,7 @@ inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField<T, Block
|
||||
{
|
||||
BaseEntity* 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())
|
||||
|
||||
@@ -64,9 +64,9 @@ 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_entityFragments.Add(WowCS::EntityFragment::CGObject, false,
|
||||
&Object::BuildObjectFragmentCreate, &Object::BuildObjectFragmentUpdate, &Object::IsObjectFragmentChanged);
|
||||
}
|
||||
|
||||
Object::~Object() = default;
|
||||
@@ -103,10 +103,15 @@ void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::Updat
|
||||
|
||||
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
|
||||
uint8 contentsChangedMask = 0;
|
||||
for (std::size_t i = 0; i < m_entityFragments.UpdateableCount; ++i)
|
||||
{
|
||||
if (WowCS::IsIndirectFragment(m_entityFragments.Updateable.Ids[i]))
|
||||
contentsChangedMask |= m_entityFragments.Updateable.Masks[i] >> 1; // set the "fragment exists" bit
|
||||
|
||||
if (m_entityFragments.Updateable.Ids[i] == WowCS::EntityFragment::CGObject)
|
||||
contentsChangedMask |= m_entityFragments.Updateable.Masks[i];
|
||||
}
|
||||
|
||||
*data << uint8(flags.HasFlag(UF::UpdateFieldFlag::Owner));
|
||||
*data << uint8(false); // m_entityFragments.IdsChanged
|
||||
@@ -124,6 +129,21 @@ void Object::ClearUpdateMask(bool remove)
|
||||
BaseEntity::ClearUpdateMask(remove);
|
||||
}
|
||||
|
||||
void Object::BuildObjectFragmentCreate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
|
||||
{
|
||||
static_cast<Object const*>(entity)->BuildValuesCreate(&data, flags, target);
|
||||
}
|
||||
|
||||
void Object::BuildObjectFragmentUpdate(BaseEntity const* entity, ByteBuffer& data, UF::UpdateFieldFlag flags, Player const* target)
|
||||
{
|
||||
static_cast<Object const*>(entity)->BuildValuesUpdate(&data, flags, target);
|
||||
}
|
||||
|
||||
bool Object::IsObjectFragmentChanged(BaseEntity const* entity)
|
||||
{
|
||||
return entity->m_values.GetChangedObjectTypeMask() != 0;
|
||||
}
|
||||
|
||||
std::string Object::GetDebugInfo() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
@@ -3097,6 +3117,8 @@ struct WorldObjectChangeAccumulator
|
||||
|
||||
void WorldObject::BuildUpdate(UpdateDataMapType& data_map)
|
||||
{
|
||||
Object::BuildUpdateChangesMask();
|
||||
|
||||
WorldObjectChangeAccumulator notifier(*this, data_map);
|
||||
WorldObjectVisibleChangeVisitor visitor(notifier);
|
||||
//we must build packets for all visible players
|
||||
|
||||
@@ -173,14 +173,17 @@ class TC_GAME_API Object : public BaseEntity
|
||||
protected:
|
||||
Object();
|
||||
|
||||
void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override = 0;
|
||||
void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override = 0;
|
||||
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;
|
||||
void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags) const;
|
||||
|
||||
public:
|
||||
virtual void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const;
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
@@ -78,7 +78,7 @@ 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 + 1> ObjectTypeMask =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct UpdateableFragments
|
||||
{
|
||||
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 = { };
|
||||
};
|
||||
|
||||
UpdateableFragments<4> Updateable;
|
||||
|
||||
uint8 Count = 0;
|
||||
bool IdsChanged = false;
|
||||
|
||||
std::array<EntityFragment, 4> UpdateableIds =
|
||||
{
|
||||
EntityFragment::End, EntityFragment::End, EntityFragment::End, EntityFragment::End
|
||||
};
|
||||
std::array<uint8, 4> UpdateableMasks = { };
|
||||
uint8 UpdateableCount = 0;
|
||||
uint8 ContentsChangedMask = 0;
|
||||
|
||||
void Add(EntityFragment fragment, bool update);
|
||||
void Add(EntityFragment fragment, bool update,
|
||||
EntityFragmentSerializeFn serializeCreate, EntityFragmentSerializeFn serializeUpdate, EntityFragmentIsChangedFn isChanged);
|
||||
|
||||
inline void Add(EntityFragment fragment, bool update) { Add(fragment, update, nullptr, nullptr, nullptr); }
|
||||
|
||||
template <typename SerializationTraits>
|
||||
inline void Add(EntityFragment fragment, bool update, SerializationTraits)
|
||||
{
|
||||
Add(fragment, update, &SerializationTraits::BuildCreate, &SerializationTraits::BuildUpdate, &SerializationTraits::IsChanged);
|
||||
}
|
||||
|
||||
void Remove(EntityFragment fragment);
|
||||
|
||||
std::span<EntityFragment const> GetIds() const { return std::span(Ids.begin(), Count); }
|
||||
std::span<EntityFragment const> GetUpdateableIds() const { return std::span(UpdateableIds.begin(), UpdateableCount); }
|
||||
|
||||
uint8 GetUpdateMaskFor(EntityFragment fragment) const
|
||||
{
|
||||
if (fragment == EntityFragment::CGObject) // common case optimization, make use of the fact that fragment arrays are sorted
|
||||
return CGObjectChangedMask;
|
||||
|
||||
for (uint8 i = 1; i < UpdateableCount; ++i)
|
||||
if (UpdateableIds[i] == fragment)
|
||||
return UpdateableMasks[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
enum class EntityFragmentSerializationType : uint8
|
||||
|
||||
@@ -689,6 +689,8 @@ void Transport::UpdatePassengerPositions(PassengerSet const& passengers)
|
||||
|
||||
void Transport::BuildUpdate(UpdateDataMapType& data_map)
|
||||
{
|
||||
Object::BuildUpdateChangesMask();
|
||||
|
||||
for (MapReference const& playerReference : GetMap()->GetPlayers())
|
||||
if (playerReference.GetSource()->InSamePhase(this))
|
||||
BuildFieldsUpdate(playerReference.GetSource(), data_map);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user