Core/PacketIO: Updated SMSG_UPDATE_OBJECT for 11.0.5
This commit is contained in:
@@ -53,6 +53,8 @@ AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurE
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.AreaTrigger = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_AreaTrigger, false);
|
||||
}
|
||||
|
||||
AreaTrigger::~AreaTrigger()
|
||||
@@ -1396,6 +1398,7 @@ void AreaTrigger::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags,
|
||||
void AreaTrigger::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::AreaTriggerData::Mask const& requestedAreaTriggerMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -1406,6 +1409,7 @@ void AreaTrigger::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Objec
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -166,7 +166,7 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area
|
||||
|
||||
void UpdateShape();
|
||||
|
||||
UF::UpdateField<UF::AreaTriggerData, 0, TYPEID_AREATRIGGER> m_areaTriggerData;
|
||||
UF::UpdateField<UF::AreaTriggerData, int32(WowCS::EntityFragment::CGObject), TYPEID_AREATRIGGER> m_areaTriggerData;
|
||||
|
||||
protected:
|
||||
void _UpdateDuration(int32 newDuration);
|
||||
|
||||
@@ -39,6 +39,8 @@ Conversation::Conversation() : WorldObject(false), _duration(0), _textureKitId(0
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.Conversation = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Conversation, false);
|
||||
|
||||
_lastLineEndTimes.fill(Milliseconds::zero());
|
||||
}
|
||||
|
||||
@@ -367,6 +369,7 @@ void Conversation::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags
|
||||
void Conversation::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::ConversationData::Mask const& requestedConversationMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -377,6 +380,7 @@ void Conversation::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Obje
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -87,7 +87,7 @@ class TC_GAME_API Conversation final : public WorldObject, public GridObject<Con
|
||||
|
||||
uint32 GetScriptId() const;
|
||||
|
||||
UF::UpdateField<UF::ConversationData, 0, TYPEID_CONVERSATION> m_conversationData;
|
||||
UF::UpdateField<UF::ConversationData, int32(WowCS::EntityFragment::CGObject), TYPEID_CONVERSATION> m_conversationData;
|
||||
|
||||
private:
|
||||
Position _stationaryPosition;
|
||||
|
||||
@@ -37,6 +37,8 @@ Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Corpse, false);
|
||||
|
||||
m_time = GameTime::GetGameTime();
|
||||
|
||||
lootRecipient = nullptr;
|
||||
@@ -258,6 +260,7 @@ void Corpse::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Play
|
||||
void Corpse::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::CorpseData::Mask const& requestedCorpseMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -268,6 +271,7 @@ void Corpse::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -135,7 +135,7 @@ class TC_GAME_API Corpse final : public WorldObject, public GridObject<Corpse>
|
||||
|
||||
bool IsExpired(time_t t) const;
|
||||
|
||||
UF::UpdateField<UF::CorpseData, 0, TYPEID_CORPSE> m_corpseData;
|
||||
UF::UpdateField<UF::CorpseData, int32(WowCS::EntityFragment::CGObject), TYPEID_CORPSE> m_corpseData;
|
||||
|
||||
private:
|
||||
CorpseType m_type;
|
||||
|
||||
@@ -606,9 +606,17 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
|
||||
if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT)
|
||||
npcFlags |= sGameEventMgr->GetNPCFlag(this);
|
||||
|
||||
if (IsVendor() && !(npcFlags & UNIT_NPC_FLAG_VENDOR_MASK))
|
||||
SetVendor(UNIT_NPC_FLAG_VENDOR_MASK, false);
|
||||
|
||||
ReplaceAllNpcFlags(NPCFlags(npcFlags & 0xFFFFFFFF));
|
||||
ReplaceAllNpcFlags2(NPCFlags2(npcFlags >> 32));
|
||||
|
||||
if (npcFlags & UNIT_NPC_FLAG_VENDOR_MASK)
|
||||
SetVendor(NPCFlags(npcFlags & UNIT_NPC_FLAG_VENDOR_MASK), true);
|
||||
|
||||
SetPetitioner((npcFlags & UNIT_NPC_FLAG_PETITIONER) != 0);
|
||||
|
||||
// if unit is in combat, keep this flag
|
||||
unitFlags &= ~UNIT_FLAG_IN_COMBAT;
|
||||
if (IsInCombat())
|
||||
@@ -3255,6 +3263,52 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
|
||||
return vCount->count;
|
||||
}
|
||||
|
||||
void Creature::SetVendor(NPCFlags flags, bool apply)
|
||||
{
|
||||
flags &= UNIT_NPC_FLAG_VENDOR_MASK;
|
||||
VendorDataTypeFlags vendorFlags = static_cast<VendorDataTypeFlags>(AsUnderlyingType(flags) >> 7);
|
||||
if (apply)
|
||||
{
|
||||
if (!m_vendorData)
|
||||
m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld());
|
||||
|
||||
SetNpcFlag(flags);
|
||||
SetUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(vendorFlags));
|
||||
}
|
||||
else if (m_vendorData)
|
||||
{
|
||||
RemoveNpcFlag(flags);
|
||||
RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(vendorFlags));
|
||||
if (!m_vendorData->Flags)
|
||||
{
|
||||
RemoveOptionalUpdateFieldValue(m_values.ModifyValue(&Creature::m_vendorData));
|
||||
m_entityFragments.Remove(WowCS::EntityFragment::FVendor_C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::SetPetitioner(bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
if (!m_vendorData)
|
||||
m_entityFragments.Add(WowCS::EntityFragment::FVendor_C, IsInWorld());
|
||||
|
||||
SetNpcFlag(UNIT_NPC_FLAG_PETITIONER);
|
||||
SetUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(VendorDataTypeFlags::Petition));
|
||||
}
|
||||
else if (m_vendorData)
|
||||
{
|
||||
RemoveNpcFlag(UNIT_NPC_FLAG_PETITIONER);
|
||||
RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Creature::m_vendorData, 0).ModifyValue(&UF::VendorData::Flags), AsUnderlyingType(VendorDataTypeFlags::Petition));
|
||||
if (!m_vendorData->Flags)
|
||||
{
|
||||
RemoveOptionalUpdateFieldValue(m_values.ModifyValue(&Creature::m_vendorData));
|
||||
m_entityFragments.Remove(WowCS::EntityFragment::FVendor_C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
std::string Creature::GetNameForLocaleIdx(LocaleConstant locale) const
|
||||
{
|
||||
@@ -3775,17 +3829,26 @@ 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)
|
||||
m_vendorData->WriteCreate(*data, flags, this, target);
|
||||
}
|
||||
|
||||
void Creature::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
|
||||
{
|
||||
*data << uint32(m_values.GetChangedObjectTypeMask());
|
||||
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);
|
||||
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_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);
|
||||
}
|
||||
|
||||
void Creature::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
|
||||
@@ -3816,6 +3879,7 @@ void Creature::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectDa
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
@@ -3839,3 +3903,11 @@ void Creature::ValuesUpdateForPlayerWithMaskSender::operator()(Player const* pla
|
||||
udata.BuildPacket(&packet);
|
||||
player->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Creature::ClearUpdateMask(bool remove)
|
||||
{
|
||||
if (m_vendorData)
|
||||
m_values.ClearChangesMask(&Creature::m_vendorData);
|
||||
|
||||
Unit::ClearUpdateMask(remove);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,18 @@ enum class VendorInventoryReason : uint8
|
||||
Empty = 1
|
||||
};
|
||||
|
||||
enum class VendorDataTypeFlags : int32
|
||||
{
|
||||
Generic = 0x01,
|
||||
Ammo = 0x02,
|
||||
Food = 0x04,
|
||||
Poison = 0x08,
|
||||
Reagent = 0x10,
|
||||
Petition = 0x20,
|
||||
};
|
||||
|
||||
DEFINE_ENUM_FLAG(VendorDataTypeFlags);
|
||||
|
||||
static constexpr uint8 WILD_BATTLE_PET_DEFAULT_LEVEL = 1;
|
||||
static constexpr size_t CREATURE_TAPPERS_SOFT_CAP = 5;
|
||||
|
||||
@@ -248,6 +260,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
VendorItemData const* GetVendorItems() const;
|
||||
uint32 GetVendorItemCurrentCount(VendorItem const* vItem);
|
||||
uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count);
|
||||
void SetVendor(NPCFlags flags, bool apply);
|
||||
void SetPetitioner(bool apply);
|
||||
|
||||
CreatureTemplate const* GetCreatureTemplate() const { return m_creatureInfo; }
|
||||
CreatureData const* GetCreatureData() const { return m_creatureData; }
|
||||
@@ -468,6 +482,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
void InitializeInteractSpellId();
|
||||
void SetInteractSpellId(int32 interactSpellId) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::InteractSpellID), interactSpellId); }
|
||||
|
||||
UF::OptionalUpdateField<UF::VendorData, int32(WowCS::EntityFragment::FVendor_C), 0> m_vendorData;
|
||||
|
||||
protected:
|
||||
void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override;
|
||||
void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override;
|
||||
@@ -489,6 +505,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
};
|
||||
|
||||
protected:
|
||||
void ClearUpdateMask(bool remove) override;
|
||||
|
||||
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0);
|
||||
bool InitEntry(uint32 entry, CreatureData const* data = nullptr);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject),
|
||||
m_objectTypeId = TYPEID_DYNAMICOBJECT;
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_DynamicObject, false);
|
||||
}
|
||||
|
||||
DynamicObject::~DynamicObject()
|
||||
@@ -272,6 +274,7 @@ void DynamicObject::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flag
|
||||
void DynamicObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::DynamicObjectData::Mask const& requestedDynamicObjectMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -282,6 +285,7 @@ void DynamicObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Obj
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -83,7 +83,7 @@ class TC_GAME_API DynamicObject final : public WorldObject, public GridObject<Dy
|
||||
ObjectGuid GetOwnerGUID() const override { return GetCasterGUID(); }
|
||||
float GetRadius() const { return m_dynamicObjectData->Radius; }
|
||||
|
||||
UF::UpdateField<UF::DynamicObjectData, 0, TYPEID_DYNAMICOBJECT> m_dynamicObjectData;
|
||||
UF::UpdateField<UF::DynamicObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_DYNAMICOBJECT> m_dynamicObjectData;
|
||||
|
||||
protected:
|
||||
Aura* _aura;
|
||||
|
||||
@@ -844,6 +844,8 @@ GameObject::GameObject() : WorldObject(false), MapObject(),
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.Rotation = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_GameObject, false);
|
||||
|
||||
m_respawnTime = 0;
|
||||
m_respawnDelayTime = 300;
|
||||
m_despawnDelay = 0;
|
||||
@@ -1102,6 +1104,7 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
|
||||
}
|
||||
case GAMEOBJECT_TYPE_TRANSPORT:
|
||||
{
|
||||
m_updateFlag.GameObject = true;
|
||||
m_goTypeImpl = std::make_unique<GameObjectType::Transport>(*this);
|
||||
if (goInfo->transport.startOpen)
|
||||
SetGoState(GO_STATE_TRANSPORT_STOPPED);
|
||||
@@ -4043,6 +4046,7 @@ void GameObject::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags,
|
||||
void GameObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::GameObjectData::Mask const& requestedGameObjectMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -4053,6 +4057,7 @@ void GameObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Object
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
@@ -4093,20 +4098,7 @@ std::vector<uint32> const* GameObject::GetPauseTimes() const
|
||||
|
||||
void GameObject::SetPathProgressForClient(float progress)
|
||||
{
|
||||
DoWithSuppressingObjectUpdates([&]()
|
||||
{
|
||||
UF::ObjectData::Base dynflagMask;
|
||||
dynflagMask.MarkChanged(&UF::ObjectData::DynamicFlags);
|
||||
bool marked = (m_objectData->GetChangesMask() & dynflagMask.GetChangesMask()).IsAnySet();
|
||||
|
||||
uint32 dynamicFlags = GetDynamicFlags();
|
||||
dynamicFlags &= 0xFFFF; // remove high bits
|
||||
dynamicFlags |= uint32(progress * 65535.0f) << 16;
|
||||
ReplaceAllDynamicFlags(dynamicFlags);
|
||||
|
||||
if (!marked)
|
||||
const_cast<UF::ObjectData&>(*m_objectData).ClearChanged(&UF::ObjectData::DynamicFlags);
|
||||
});
|
||||
m_transportPathProgress = progress;
|
||||
}
|
||||
|
||||
void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = nullptr*/) const
|
||||
|
||||
@@ -289,6 +289,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
static void SetGoArtKit(uint32 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0));
|
||||
|
||||
std::vector<uint32> const* GetPauseTimes() const;
|
||||
Optional<float> GetPathProgressForClient() const { return m_transportPathProgress; }
|
||||
void SetPathProgressForClient(float progress);
|
||||
|
||||
void EnableCollision(bool enable);
|
||||
@@ -451,7 +452,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
|
||||
void HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const& command) const;
|
||||
|
||||
UF::UpdateField<UF::GameObjectData, 0, TYPEID_GAMEOBJECT> m_gameObjectData;
|
||||
UF::UpdateField<UF::GameObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_GAMEOBJECT> m_gameObjectData;
|
||||
|
||||
TeamId GetControllingTeam() const;
|
||||
|
||||
@@ -514,6 +515,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
bool m_respawnCompatibilityMode;
|
||||
uint16 _animKitId;
|
||||
uint32 _worldEffectID;
|
||||
Optional<float> m_transportPathProgress;
|
||||
|
||||
std::unique_ptr<Vignettes::VignetteData> m_vignette;
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ AzeriteEmpoweredItem::AzeriteEmpoweredItem()
|
||||
m_objectType |= TYPEMASK_AZERITE_EMPOWERED_ITEM;
|
||||
m_objectTypeId = TYPEID_AZERITE_EMPOWERED_ITEM;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_AzeriteEmpoweredItem, false);
|
||||
|
||||
m_azeritePowers = nullptr;
|
||||
m_maxTier = 0;
|
||||
}
|
||||
@@ -194,6 +196,7 @@ void AzeriteEmpoweredItem::BuildValuesUpdateForPlayerWithMask(UpdateData* data,
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
void operator()(Player const* player) const;
|
||||
};
|
||||
|
||||
UF::UpdateField<UF::AzeriteEmpoweredItemData, 0, TYPEID_AZERITE_EMPOWERED_ITEM> m_azeriteEmpoweredItemData;
|
||||
UF::UpdateField<UF::AzeriteEmpoweredItemData, int32(WowCS::EntityFragment::CGObject), TYPEID_AZERITE_EMPOWERED_ITEM> m_azeriteEmpoweredItemData;
|
||||
|
||||
private:
|
||||
void InitAzeritePowerData();
|
||||
|
||||
@@ -32,6 +32,8 @@ AzeriteItem::AzeriteItem() : Item()
|
||||
m_objectType |= TYPEMASK_AZERITE_ITEM;
|
||||
m_objectTypeId = TYPEID_AZERITE_ITEM;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_AzeriteItem, false);
|
||||
|
||||
SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::DEBUGknowledgeWeek), -1);
|
||||
}
|
||||
|
||||
@@ -448,6 +450,7 @@ void AzeriteItem::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Objec
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
void operator()(Player const* player) const;
|
||||
};
|
||||
|
||||
UF::UpdateField<UF::AzeriteItemData, 0, TYPEID_AZERITE_ITEM> m_azeriteItemData;
|
||||
UF::UpdateField<UF::AzeriteItemData, int32(WowCS::EntityFragment::CGObject), TYPEID_AZERITE_ITEM> m_azeriteItemData;
|
||||
|
||||
private:
|
||||
void UnlockDefaultMilestones();
|
||||
|
||||
@@ -30,6 +30,8 @@ Bag::Bag(): Item()
|
||||
m_objectType |= TYPEMASK_CONTAINER;
|
||||
m_objectTypeId = TYPEID_CONTAINER;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Container, false);
|
||||
|
||||
memset(m_bagslot, 0, sizeof(Item*) * MAX_BAG_SIZE);
|
||||
}
|
||||
|
||||
@@ -222,6 +224,7 @@ void Bag::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::M
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -76,7 +76,7 @@ class TC_GAME_API Bag : public Item
|
||||
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
UF::UpdateField<UF::ContainerData, 0, TYPEID_CONTAINER> m_containerData;
|
||||
UF::UpdateField<UF::ContainerData, int32(WowCS::EntityFragment::CGObject), TYPEID_CONTAINER> m_containerData;
|
||||
|
||||
protected:
|
||||
void SetBagSize(uint32 numSlots) { SetUpdateFieldValue(m_values.ModifyValue(&Bag::m_containerData).ModifyValue(&UF::ContainerData::NumSlots), numSlots); }
|
||||
|
||||
@@ -446,6 +446,8 @@ Item::Item()
|
||||
m_objectType |= TYPEMASK_ITEM;
|
||||
m_objectTypeId = TYPEID_ITEM;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Item, false);
|
||||
|
||||
m_slot = 0;
|
||||
uState = ITEM_NEW;
|
||||
uQueuePos = -1;
|
||||
@@ -1749,6 +1751,7 @@ void Item::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -448,7 +448,7 @@ class TC_GAME_API Item : public Object
|
||||
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
UF::UpdateField<UF::ItemData, 0, TYPEID_ITEM> m_itemData;
|
||||
UF::UpdateField<UF::ItemData, uint32(WowCS::EntityFragment::CGObject), TYPEID_ITEM> m_itemData;
|
||||
|
||||
protected:
|
||||
BonusData _bonusData;
|
||||
|
||||
@@ -76,6 +76,8 @@ Object::Object() : m_scriptRef(this, NoopObjectDeleter())
|
||||
m_objectType = TYPEMASK_OBJECT;
|
||||
m_updateFlag.Clear();
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::CGObject, false);
|
||||
|
||||
m_inWorld = false;
|
||||
m_isNewObject = false;
|
||||
m_isDestroyedObject = false;
|
||||
@@ -182,6 +184,8 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
|
||||
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);
|
||||
|
||||
@@ -209,6 +213,15 @@ void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* tar
|
||||
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);
|
||||
|
||||
@@ -221,12 +234,26 @@ void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::Updat
|
||||
|
||||
std::size_t sizePos = buf.wpos();
|
||||
buf << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buf, flags);
|
||||
BuildValuesUpdateWithFlag(&buf, flags, target);
|
||||
buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
|
||||
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void Object::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
|
||||
{
|
||||
data->append(fragments.data(), fragments.size());
|
||||
*data << WorldPackets::As<uint8>(WowCS::EntityFragment::End);
|
||||
}
|
||||
|
||||
void Object::BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags)
|
||||
{
|
||||
*data << uint8(flags.HasFlag(UF::UpdateFieldFlag::Owner));
|
||||
*data << uint8(false); // m_entityFragments.IdsChanged
|
||||
*data << uint8(WowCS::CGObjectUpdateMask);
|
||||
}
|
||||
|
||||
void Object::BuildDestroyUpdateBlock(UpdateData* data) const
|
||||
{
|
||||
data->AddDestroyObject(GetGUID());
|
||||
@@ -273,6 +300,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
if (GameObject const* go = ToGameObject())
|
||||
PauseTimes = go->GetPauseTimes();
|
||||
|
||||
data->WriteBit(IsWorldObject()); // HasPositionFragment
|
||||
data->WriteBit(flags.NoBirthAnim);
|
||||
data->WriteBit(flags.EnablePortals);
|
||||
data->WriteBit(flags.PlayHoverAnim);
|
||||
@@ -469,6 +497,66 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
|
||||
*data << areaTrigger->GetRollPitchYaw().PositionXYZStream();
|
||||
|
||||
switch (shape.Type)
|
||||
{
|
||||
case AreaTriggerShapeType::Sphere:
|
||||
*data << int8(0);
|
||||
*data << float(shape.SphereDatas.Radius);
|
||||
*data << float(shape.SphereDatas.RadiusTarget);
|
||||
break;
|
||||
case AreaTriggerShapeType::Box:
|
||||
*data << int8(1);
|
||||
*data << float(shape.BoxDatas.Extents[0]);
|
||||
*data << float(shape.BoxDatas.Extents[1]);
|
||||
*data << float(shape.BoxDatas.Extents[2]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[0]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[1]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[2]);
|
||||
break;
|
||||
case AreaTriggerShapeType::Polygon:
|
||||
*data << int8(3);
|
||||
*data << int32(shape.PolygonVertices.size());
|
||||
*data << int32(shape.PolygonVerticesTarget.size());
|
||||
*data << float(shape.PolygonDatas.Height);
|
||||
*data << float(shape.PolygonDatas.HeightTarget);
|
||||
|
||||
for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVertices)
|
||||
*data << vertice;
|
||||
|
||||
for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVerticesTarget)
|
||||
*data << vertice;
|
||||
break;
|
||||
case AreaTriggerShapeType::Cylinder:
|
||||
*data << int8(4);
|
||||
*data << float(shape.CylinderDatas.Radius);
|
||||
*data << float(shape.CylinderDatas.RadiusTarget);
|
||||
*data << float(shape.CylinderDatas.Height);
|
||||
*data << float(shape.CylinderDatas.HeightTarget);
|
||||
*data << float(shape.CylinderDatas.LocationZOffset);
|
||||
*data << float(shape.CylinderDatas.LocationZOffsetTarget);
|
||||
break;
|
||||
case AreaTriggerShapeType::Disk:
|
||||
*data << int8(7);
|
||||
*data << float(shape.DiskDatas.InnerRadius);
|
||||
*data << float(shape.DiskDatas.InnerRadiusTarget);
|
||||
*data << float(shape.DiskDatas.OuterRadius);
|
||||
*data << float(shape.DiskDatas.OuterRadiusTarget);
|
||||
*data << float(shape.DiskDatas.Height);
|
||||
*data << float(shape.DiskDatas.HeightTarget);
|
||||
*data << float(shape.DiskDatas.LocationZOffset);
|
||||
*data << float(shape.DiskDatas.LocationZOffsetTarget);
|
||||
break;
|
||||
case AreaTriggerShapeType::BoundedPlane:
|
||||
*data << int8(8);
|
||||
*data << float(shape.BoundedPlaneDatas.Extents[0]);
|
||||
*data << float(shape.BoundedPlaneDatas.Extents[1]);
|
||||
*data << float(shape.BoundedPlaneDatas.ExtentsTarget[0]);
|
||||
*data << float(shape.BoundedPlaneDatas.ExtentsTarget[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bool hasAbsoluteOrientation = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation);
|
||||
bool hasDynamicShape = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasDynamicShape);
|
||||
bool hasAttached = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached);
|
||||
@@ -481,12 +569,6 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
bool hasMorphCurveID = createProperties && createProperties->MorphCurveId != 0;
|
||||
bool hasFacingCurveID = createProperties && createProperties->FacingCurveId != 0;
|
||||
bool hasMoveCurveID = createProperties && createProperties->MoveCurveId != 0;
|
||||
bool hasAreaTriggerSphere = shape.IsSphere();
|
||||
bool hasAreaTriggerBox = shape.IsBox();
|
||||
bool hasAreaTriggerPolygon = shape.IsPolygon();
|
||||
bool hasAreaTriggerCylinder = shape.IsCylinder();
|
||||
bool hasDisk = shape.IsDisk();
|
||||
bool hasBoundedPlane = shape.IsBoundedPlane();
|
||||
bool hasAreaTriggerSpline = areaTrigger->HasSplines();
|
||||
bool hasOrbit = areaTrigger->HasOrbit();
|
||||
bool hasMovementScript = false;
|
||||
@@ -505,12 +587,6 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
data->WriteBit(hasFacingCurveID);
|
||||
data->WriteBit(hasMoveCurveID);
|
||||
data->WriteBit(hasPositionalSoundKitID);
|
||||
data->WriteBit(hasAreaTriggerSphere);
|
||||
data->WriteBit(hasAreaTriggerBox);
|
||||
data->WriteBit(hasAreaTriggerPolygon);
|
||||
data->WriteBit(hasAreaTriggerCylinder);
|
||||
data->WriteBit(hasDisk);
|
||||
data->WriteBit(hasBoundedPlane);
|
||||
data->WriteBit(hasAreaTriggerSpline);
|
||||
data->WriteBit(hasOrbit);
|
||||
data->WriteBit(hasMovementScript);
|
||||
@@ -543,66 +619,6 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
if (hasPositionalSoundKitID)
|
||||
*data << uint32(0);
|
||||
|
||||
if (hasAreaTriggerSphere)
|
||||
{
|
||||
*data << float(shape.SphereDatas.Radius);
|
||||
*data << float(shape.SphereDatas.RadiusTarget);
|
||||
}
|
||||
|
||||
if (hasAreaTriggerBox)
|
||||
{
|
||||
*data << float(shape.BoxDatas.Extents[0]);
|
||||
*data << float(shape.BoxDatas.Extents[1]);
|
||||
*data << float(shape.BoxDatas.Extents[2]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[0]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[1]);
|
||||
*data << float(shape.BoxDatas.ExtentsTarget[2]);
|
||||
}
|
||||
|
||||
if (hasAreaTriggerPolygon)
|
||||
{
|
||||
*data << int32(shape.PolygonVertices.size());
|
||||
*data << int32(shape.PolygonVerticesTarget.size());
|
||||
*data << float(shape.PolygonDatas.Height);
|
||||
*data << float(shape.PolygonDatas.HeightTarget);
|
||||
|
||||
for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVertices)
|
||||
*data << vertice;
|
||||
|
||||
for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVerticesTarget)
|
||||
*data << vertice;
|
||||
}
|
||||
|
||||
if (hasAreaTriggerCylinder)
|
||||
{
|
||||
*data << float(shape.CylinderDatas.Radius);
|
||||
*data << float(shape.CylinderDatas.RadiusTarget);
|
||||
*data << float(shape.CylinderDatas.Height);
|
||||
*data << float(shape.CylinderDatas.HeightTarget);
|
||||
*data << float(shape.CylinderDatas.LocationZOffset);
|
||||
*data << float(shape.CylinderDatas.LocationZOffsetTarget);
|
||||
}
|
||||
|
||||
if (hasDisk)
|
||||
{
|
||||
*data << float(shape.DiskDatas.InnerRadius);
|
||||
*data << float(shape.DiskDatas.InnerRadiusTarget);
|
||||
*data << float(shape.DiskDatas.OuterRadius);
|
||||
*data << float(shape.DiskDatas.OuterRadiusTarget);
|
||||
*data << float(shape.DiskDatas.Height);
|
||||
*data << float(shape.DiskDatas.HeightTarget);
|
||||
*data << float(shape.DiskDatas.LocationZOffset);
|
||||
*data << float(shape.DiskDatas.LocationZOffsetTarget);
|
||||
}
|
||||
|
||||
if (hasBoundedPlane)
|
||||
{
|
||||
*data << float(shape.BoundedPlaneDatas.Extents[0]);
|
||||
*data << float(shape.BoundedPlaneDatas.Extents[1]);
|
||||
*data << float(shape.BoundedPlaneDatas.ExtentsTarget[0]);
|
||||
*data << float(shape.BoundedPlaneDatas.ExtentsTarget[1]);
|
||||
}
|
||||
|
||||
//if (hasMovementScript)
|
||||
// *data << *areaTrigger->GetMovementScript(); // AreaTriggerMovementScriptInfo
|
||||
|
||||
@@ -612,17 +628,32 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe
|
||||
|
||||
if (flags.GameObject)
|
||||
{
|
||||
bool bit8 = false;
|
||||
uint32 Int1 = 0;
|
||||
|
||||
GameObject const* gameObject = ToGameObject();
|
||||
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)
|
||||
{
|
||||
*data << uint32(transport->GetTransportPeriod());
|
||||
*data << uint32(transport->GetTimer());
|
||||
data->WriteBit(transport->IsStopRequested());
|
||||
data->WriteBit(transport->IsStopped());
|
||||
data->WriteBit(false);
|
||||
data->FlushBits();
|
||||
}
|
||||
|
||||
if (bit8)
|
||||
*data << uint32(Int1);
|
||||
*data << uint32(0);
|
||||
|
||||
if (gameObject->GetPathProgressForClient())
|
||||
*data << float(*gameObject->GetPathProgressForClient());
|
||||
}
|
||||
|
||||
if (flags.SmoothPhasing)
|
||||
@@ -806,6 +837,8 @@ void Object::AddToObjectUpdateIfNeeded()
|
||||
void Object::ClearUpdateMask(bool remove)
|
||||
{
|
||||
m_values.ClearChangesMask(&Object::m_objectData);
|
||||
m_entityFragments.IdsChanged = false;
|
||||
m_entityFragments.ContentsChangedMask = WowCS::CGObjectActiveMask;
|
||||
|
||||
if (m_objectUpdated)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "SpellDefines.h"
|
||||
#include "UniqueTrackablePtr.h"
|
||||
#include "UpdateFields.h"
|
||||
#include "WowCSEntityDefinitions.h"
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -113,9 +114,18 @@ namespace UF
|
||||
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; }
|
||||
@@ -290,7 +300,7 @@ class TC_GAME_API Object
|
||||
|
||||
friend UF::UpdateFieldHolder;
|
||||
UF::UpdateFieldHolder m_values;
|
||||
UF::UpdateField<UF::ObjectData, 0, TYPEID_OBJECT> m_objectData;
|
||||
UF::UpdateField<UF::ObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_OBJECT> m_objectData;
|
||||
|
||||
template<typename T>
|
||||
void ForceUpdateFieldChange(UF::UpdateFieldSetter<T> const& /*setter*/)
|
||||
@@ -419,6 +429,8 @@ class TC_GAME_API Object
|
||||
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);
|
||||
static void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags);
|
||||
|
||||
public:
|
||||
virtual void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const;
|
||||
@@ -428,6 +440,7 @@ class TC_GAME_API Object
|
||||
|
||||
TypeID m_objectTypeId;
|
||||
CreateObjectBits m_updateFlag;
|
||||
WowCS::EntityFragmentsHolder m_entityFragments;
|
||||
|
||||
virtual bool AddToObjectUpdate() = 0;
|
||||
virtual void RemoveFromObjectUpdate() = 0;
|
||||
@@ -468,18 +481,61 @@ 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();
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
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();
|
||||
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
(static_cast<Derived*>(owner)->*field)._value->ClearChangesMask();
|
||||
}
|
||||
|
||||
template <class T_VALUES, class T_FLAGS, class FLAG_TYPE, size_t ARRAY_SIZE>
|
||||
class FlaggedValuesArray32
|
||||
{
|
||||
|
||||
@@ -42,8 +42,9 @@ bool UpdateData::BuildPacket(WorldPacket* packet)
|
||||
ASSERT(packet->empty()); // shouldn't happen
|
||||
packet->Initialize(SMSG_UPDATE_OBJECT, 4 + 2 + 1 + (2 + 4 + 17 * (m_destroyGUIDs.size() + m_outOfRangeGUIDs.size())) + m_data.wpos());
|
||||
|
||||
*packet << uint32(m_blockCount);
|
||||
*packet << uint16(m_map);
|
||||
*packet << uint32(m_blockCount);
|
||||
packet->WriteBit(true); // unk
|
||||
|
||||
if (packet->WriteBit(!m_outOfRangeGUIDs.empty() || !m_destroyGUIDs.empty()))
|
||||
{
|
||||
|
||||
@@ -907,6 +907,8 @@ namespace UF
|
||||
template<typename F>
|
||||
friend struct OptionalUpdateFieldSetter;
|
||||
|
||||
friend class UpdateFieldHolder;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using IsLarge = std::integral_constant<bool, sizeof(void*) * 3 < sizeof(T)>;
|
||||
|
||||
@@ -1114,8 +1114,8 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi
|
||||
data << uint32(ChannelObjects.size());
|
||||
data << int32(FlightCapabilityID);
|
||||
data << float(GlideEventSpeedDivisor);
|
||||
data << uint32(MaxHealthModifierFlatNeg);
|
||||
data << uint32(MaxHealthModifierFlatPos);
|
||||
data << int32(MaxHealthModifierFlatNeg);
|
||||
data << int32(MaxHealthModifierFlatPos);
|
||||
data << uint32(SilencedSchoolMask);
|
||||
data << uint32(CurrentAreaID);
|
||||
data << float(Field_31C);
|
||||
@@ -1716,11 +1716,11 @@ void UnitData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor
|
||||
}
|
||||
if (changesMask[125])
|
||||
{
|
||||
data << uint32(MaxHealthModifierFlatNeg);
|
||||
data << int32(MaxHealthModifierFlatNeg);
|
||||
}
|
||||
if (changesMask[126])
|
||||
{
|
||||
data << uint32(MaxHealthModifierFlatPos);
|
||||
data << int32(MaxHealthModifierFlatPos);
|
||||
}
|
||||
if (changesMask[127])
|
||||
{
|
||||
@@ -2955,15 +2955,60 @@ void SkillInfo::ClearChangesMask()
|
||||
_changesMask.ResetAll();
|
||||
}
|
||||
|
||||
void BitVector::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const
|
||||
{
|
||||
data << uint32(Values.size());
|
||||
for (uint32 i = 0; i < Values.size(); ++i)
|
||||
{
|
||||
data << uint64(Values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void BitVector::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const
|
||||
{
|
||||
Mask changesMask = _changesMask;
|
||||
if (ignoreChangesMask)
|
||||
changesMask.SetAll();
|
||||
|
||||
data.WriteBits(changesMask.GetBlock(0), 2);
|
||||
|
||||
if (changesMask[0])
|
||||
{
|
||||
if (changesMask[1])
|
||||
{
|
||||
if (!ignoreChangesMask)
|
||||
Values.WriteUpdateMask(data);
|
||||
else
|
||||
WriteCompleteDynamicFieldUpdateMask(Values.size(), data);
|
||||
}
|
||||
}
|
||||
data.FlushBits();
|
||||
if (changesMask[0])
|
||||
{
|
||||
if (changesMask[1])
|
||||
{
|
||||
for (uint32 i = 0; i < Values.size(); ++i)
|
||||
{
|
||||
if (Values.HasChanged(i) || ignoreChangesMask)
|
||||
{
|
||||
data << uint64(Values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitVector::ClearChangesMask()
|
||||
{
|
||||
Base::ClearChangesMask(Values);
|
||||
_changesMask.ResetAll();
|
||||
}
|
||||
|
||||
void BitVectors::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const
|
||||
{
|
||||
for (uint32 i = 0; i < 11; ++i)
|
||||
for (uint32 i = 0; i < 13; ++i)
|
||||
{
|
||||
data << uint32(Values[i].size());
|
||||
for (uint32 j = 0; j < Values[i].size(); ++j)
|
||||
{
|
||||
data << uint64(Values[i][j]);
|
||||
}
|
||||
Values[i].WriteCreate(data, owner, receiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2973,32 +3018,21 @@ void BitVectors::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player co
|
||||
if (ignoreChangesMask)
|
||||
changesMask.SetAll();
|
||||
|
||||
data.WriteBits(changesMask.GetBlock(0), 1);
|
||||
data.WriteBits(changesMask.GetBlocksMask(0), 1);
|
||||
if (changesMask.GetBlock(0))
|
||||
data.WriteBits(changesMask.GetBlock(0), 32);
|
||||
|
||||
data.FlushBits();
|
||||
if (changesMask[0])
|
||||
{
|
||||
for (uint32 i = 0; i < 11; ++i)
|
||||
for (uint32 i = 0; i < 13; ++i)
|
||||
{
|
||||
if (!ignoreChangesMask)
|
||||
Values[i].WriteUpdateMask(data);
|
||||
else
|
||||
WriteCompleteDynamicFieldUpdateMask(Values[i].size(), data);
|
||||
}
|
||||
}
|
||||
if (changesMask[0])
|
||||
{
|
||||
for (uint32 i = 0; i < 11; ++i)
|
||||
{
|
||||
for (uint32 j = 0; j < Values[i].size(); ++j)
|
||||
if (changesMask[1 + i])
|
||||
{
|
||||
if (Values[i].HasChanged(j) || ignoreChangesMask)
|
||||
{
|
||||
data << uint64(Values[i][j]);
|
||||
}
|
||||
Values[i].WriteUpdate(data, ignoreChangesMask, owner, receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
data.FlushBits();
|
||||
}
|
||||
|
||||
void BitVectors::ClearChangesMask()
|
||||
@@ -4587,7 +4621,7 @@ bool WalkInData::operator==(WalkInData const& right) const
|
||||
void DelveData::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const
|
||||
{
|
||||
data << int32(Field_0);
|
||||
data << int64(Field_8);
|
||||
data << uint64(Field_8);
|
||||
data << int32(Field_10);
|
||||
data << int32(SpellID);
|
||||
data << uint32(Owners.size());
|
||||
@@ -4603,7 +4637,7 @@ void DelveData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player con
|
||||
{
|
||||
data.FlushBits();
|
||||
data << int32(Field_0);
|
||||
data << int64(Field_8);
|
||||
data << uint64(Field_8);
|
||||
data << int32(Field_10);
|
||||
data << int32(SpellID);
|
||||
data << uint32(Owners.size());
|
||||
@@ -4761,7 +4795,7 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f
|
||||
{
|
||||
data << uint32(BankBagSlotFlags[i]);
|
||||
}
|
||||
for (uint32 i = 0; i < 960; ++i)
|
||||
for (uint32 i = 0; i < 1000; ++i)
|
||||
{
|
||||
data << uint64(QuestCompleted[i]);
|
||||
}
|
||||
@@ -5005,8 +5039,8 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo
|
||||
{
|
||||
for (uint32 i = 0; i < 1; ++i)
|
||||
data << uint32(changesMask.GetBlocksMask(i));
|
||||
data.WriteBits(changesMask.GetBlocksMask(1), 15);
|
||||
for (uint32 i = 0; i < 47; ++i)
|
||||
data.WriteBits(changesMask.GetBlocksMask(1), 16);
|
||||
for (uint32 i = 0; i < 48; ++i)
|
||||
if (changesMask.GetBlock(i))
|
||||
data.WriteBits(changesMask.GetBlock(i), 32);
|
||||
|
||||
@@ -6232,7 +6266,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo
|
||||
}
|
||||
if (changesMask[497])
|
||||
{
|
||||
for (uint32 i = 0; i < 960; ++i)
|
||||
for (uint32 i = 0; i < 1000; ++i)
|
||||
{
|
||||
if (changesMask[498 + i])
|
||||
{
|
||||
@@ -6240,11 +6274,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changesMask[1458])
|
||||
if (changesMask[1498])
|
||||
{
|
||||
for (uint32 i = 0; i < 17; ++i)
|
||||
{
|
||||
if (changesMask[1459 + i])
|
||||
if (changesMask[1499 + i])
|
||||
{
|
||||
data << float(ItemUpgradeHighWatermark[i]);
|
||||
}
|
||||
@@ -7329,6 +7363,36 @@ void ConversationData::ClearChangesMask()
|
||||
_changesMask.ResetAll();
|
||||
}
|
||||
|
||||
void VendorData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Creature const* owner, Player const* receiver) const
|
||||
{
|
||||
data << int32(Flags);
|
||||
}
|
||||
|
||||
void VendorData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Creature const* owner, Player const* receiver) const
|
||||
{
|
||||
WriteUpdate(data, _changesMask, false, owner, receiver);
|
||||
}
|
||||
|
||||
void VendorData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Creature const* owner, Player const* receiver) const
|
||||
{
|
||||
data.WriteBits(changesMask.GetBlock(0), 2);
|
||||
|
||||
data.FlushBits();
|
||||
if (changesMask[0])
|
||||
{
|
||||
if (changesMask[1])
|
||||
{
|
||||
data << int32(Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VendorData::ClearChangesMask()
|
||||
{
|
||||
Base::ClearChangesMask(Flags);
|
||||
_changesMask.ResetAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
|
||||
@@ -37,6 +37,7 @@ class Bag;
|
||||
class ByteBuffer;
|
||||
class Conversation;
|
||||
class Corpse;
|
||||
class Creature;
|
||||
class DynamicObject;
|
||||
class GameObject;
|
||||
class Item;
|
||||
@@ -390,8 +391,8 @@ struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<220>
|
||||
UpdateField<ObjectGuid, 96, 122> GuildGUID;
|
||||
UpdateField<int32, 96, 123> FlightCapabilityID;
|
||||
UpdateField<float, 96, 124> GlideEventSpeedDivisor; // Movement speed gets divided by this value when evaluating what GlideEvents to use
|
||||
UpdateField<uint32, 96, 125> MaxHealthModifierFlatNeg;
|
||||
UpdateField<uint32, 96, 126> MaxHealthModifierFlatPos;
|
||||
UpdateField<int32, 96, 125> MaxHealthModifierFlatNeg;
|
||||
UpdateField<int32, 96, 126> MaxHealthModifierFlatPos;
|
||||
UpdateField<uint32, 96, 127> SilencedSchoolMask;
|
||||
UpdateField<uint32, 128, 129> CurrentAreaID;
|
||||
UpdateField<float, 128, 130> Field_31C;
|
||||
@@ -590,9 +591,18 @@ struct SkillInfo : public IsUpdateFieldStructureTag, public HasChangesMask<1793>
|
||||
void ClearChangesMask();
|
||||
};
|
||||
|
||||
struct BitVectors : public IsUpdateFieldStructureTag, public HasChangesMask<1>
|
||||
struct BitVector : public IsUpdateFieldStructureTag, public HasChangesMask<2>
|
||||
{
|
||||
UpdateFieldArray<DynamicUpdateFieldBase<uint64>, 11, 0, -1> Values;
|
||||
DynamicUpdateField<uint64, 0, 1> Values;
|
||||
|
||||
void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const;
|
||||
void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const;
|
||||
void ClearChangesMask();
|
||||
};
|
||||
|
||||
struct BitVectors : public IsUpdateFieldStructureTag, public HasChangesMask<14>
|
||||
{
|
||||
UpdateFieldArray<UF::BitVector, 13, 0, 1> Values;
|
||||
|
||||
void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const;
|
||||
void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const;
|
||||
@@ -995,7 +1005,7 @@ struct DelveData : public IsUpdateFieldStructureTag
|
||||
{
|
||||
std::vector<ObjectGuid> Owners;
|
||||
int32 Field_0;
|
||||
int64 Field_8;
|
||||
uint64 Field_8;
|
||||
int32 Field_10;
|
||||
int32 SpellID;
|
||||
uint32 Started; // Restricts rewards to players in m_owners if set to true. Intended to prevent rewarwding players that join in-progress delve?
|
||||
@@ -1016,7 +1026,7 @@ struct Research : public IsUpdateFieldStructureTag
|
||||
bool operator!=(Research const& right) const { return !(*this == right); }
|
||||
};
|
||||
|
||||
struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<1476>
|
||||
struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<1516>
|
||||
{
|
||||
UpdateField<bool, 0, 1> BackpackAutoSortDisabled;
|
||||
UpdateField<bool, 0, 2> BackpackSellJunkDisabled;
|
||||
@@ -1170,8 +1180,8 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas
|
||||
UpdateFieldArray<int32, 2, 480, 481> ProfessionSkillLine;
|
||||
UpdateFieldArray<uint32, 5, 483, 484> BagSlotFlags;
|
||||
UpdateFieldArray<uint32, 7, 489, 490> BankBagSlotFlags;
|
||||
UpdateFieldArray<uint64, 960, 497, 498> QuestCompleted;
|
||||
UpdateFieldArray<float, 17, 1458, 1459> ItemUpgradeHighWatermark;
|
||||
UpdateFieldArray<uint64, 1000, 497, 498> QuestCompleted;
|
||||
UpdateFieldArray<float, 17, 1498, 1499> ItemUpgradeHighWatermark;
|
||||
|
||||
void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const;
|
||||
void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const;
|
||||
@@ -1370,6 +1380,16 @@ struct ConversationData : public IsUpdateFieldStructureTag, public HasChangesMas
|
||||
void ClearChangesMask();
|
||||
};
|
||||
|
||||
struct VendorData : public IsUpdateFieldStructureTag, public HasChangesMask<2>
|
||||
{
|
||||
UpdateField<int32, 0, 1> Flags;
|
||||
|
||||
void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Creature const* owner, Player const* receiver) const;
|
||||
void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Creature const* owner, Player const* receiver) const;
|
||||
void WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Creature const* owner, Player const* receiver) const;
|
||||
void ClearChangesMask();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // UpdateFields_h__
|
||||
|
||||
@@ -86,8 +86,7 @@ public:
|
||||
}
|
||||
else if (GameObject const* gameObject = object->ToGameObject())
|
||||
{
|
||||
uint16 dynFlags = 0;
|
||||
uint16 pathProgress = 0xFFFF;
|
||||
uint32 dynFlags = 0;
|
||||
switch (gameObject->GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_BUTTON:
|
||||
@@ -111,13 +110,6 @@ public:
|
||||
if (gameObject->HasConditionalInteraction() && gameObject->CanActivateForPlayer(receiver))
|
||||
dynFlags |= GO_DYNFLAG_LO_SPARKLE;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_TRANSPORT:
|
||||
case GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT:
|
||||
{
|
||||
dynFlags = dynamicFlags & 0xFFFF;
|
||||
pathProgress = dynamicFlags >> 16;
|
||||
break;
|
||||
}
|
||||
case GAMEOBJECT_TYPE_CAPTURE_POINT:
|
||||
if (!gameObject->CanInteractWithCapturePoint(receiver))
|
||||
dynFlags |= GO_DYNFLAG_LO_NO_INTERACT;
|
||||
@@ -147,7 +139,7 @@ public:
|
||||
dynFlags |= GO_DYNFLAG_LO_NO_INTERACT;
|
||||
}
|
||||
|
||||
dynamicFlags = (uint32(pathProgress) << 16) | uint32(dynFlags);
|
||||
dynamicFlags = dynFlags;
|
||||
}
|
||||
|
||||
return dynamicFlags;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 "WowCSEntityDefinitions.h"
|
||||
#include "Errors.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace WowCS
|
||||
{
|
||||
void EntityFragmentsHolder::Add(EntityFragment fragment, bool update)
|
||||
{
|
||||
ASSERT(Count < Ids.size());
|
||||
|
||||
auto insertSorted = [](auto& arr, uint8& count, EntityFragment f)
|
||||
{
|
||||
auto where = std::ranges::lower_bound(arr.begin(), arr.begin() + count, f);
|
||||
if (*where == f)
|
||||
return std::pair(where, false);
|
||||
std::ranges::rotate(where, arr.begin() + count, arr.begin() + count + 1);
|
||||
++count;
|
||||
*where = f;
|
||||
return std::pair(where, true);
|
||||
};
|
||||
|
||||
if (!insertSorted(Ids, Count, fragment).second)
|
||||
return;
|
||||
|
||||
if (IsUpdateableFragment(fragment))
|
||||
{
|
||||
ASSERT(UpdateableCount < UpdateableIds.size());
|
||||
|
||||
auto insertedItr = insertSorted(UpdateableIds, UpdateableCount, fragment).first;
|
||||
std::ptrdiff_t index = std::distance(UpdateableIds.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]))
|
||||
UpdateableMasks[i] |= 1 << maskIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
IdsChanged = true;
|
||||
}
|
||||
|
||||
void EntityFragmentsHolder::Remove(EntityFragment fragment)
|
||||
{
|
||||
auto removeSorted = [](auto& arr, uint8& count, EntityFragment f)
|
||||
{
|
||||
auto where = std::ranges::find(arr.begin(), arr.begin() + count, f);
|
||||
if (where != arr.end())
|
||||
{
|
||||
*where = EntityFragment::End;
|
||||
std::ranges::rotate(where, where + 1, arr.begin() + count);
|
||||
--count;
|
||||
return std::pair(where, true);
|
||||
}
|
||||
return std::pair(where, false);
|
||||
};
|
||||
|
||||
if (!removeSorted(Ids, Count, fragment).second)
|
||||
return;
|
||||
|
||||
if (IsUpdateableFragment(fragment))
|
||||
{
|
||||
auto [removedItr, removed] = removeSorted(UpdateableIds, UpdateableCount, fragment);
|
||||
if (removed)
|
||||
{
|
||||
std::ptrdiff_t index = std::distance(UpdateableIds.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]))
|
||||
UpdateableMasks[i] |= 1 << maskIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IdsChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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_WOWCS_ENTITY_DEFINITIONS_H
|
||||
#define TRINITYCORE_WOWCS_ENTITY_DEFINITIONS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <span>
|
||||
|
||||
namespace WowCS
|
||||
{
|
||||
enum class EntityFragment : uint8
|
||||
{
|
||||
CGObject = 0, // UPDATEABLE, INDIRECT,
|
||||
Tag_Item = 1, // TAG,
|
||||
Tag_Container = 2, // TAG,
|
||||
Tag_AzeriteEmpoweredItem = 3, // TAG,
|
||||
Tag_AzeriteItem = 4, // TAG,
|
||||
Tag_Unit = 5, // TAG,
|
||||
Tag_Player = 6, // TAG,
|
||||
Tag_GameObject = 7, // TAG,
|
||||
Tag_DynamicObject = 8, // TAG,
|
||||
Tag_Corpse = 9, // TAG,
|
||||
Tag_AreaTrigger = 10, // TAG,
|
||||
Tag_SceneObject = 11, // TAG,
|
||||
Tag_Conversation = 12, // TAG,
|
||||
Tag_AIGroup = 13, // TAG,
|
||||
Tag_Scenario = 14, // TAG,
|
||||
Tag_LootObject = 15, // TAG,
|
||||
Tag_ActivePlayer = 16, // TAG,
|
||||
Tag_ActiveClient_S = 17, // TAG,
|
||||
Tag_ActiveObject_C = 18, // TAG,
|
||||
Tag_VisibleObject_C = 19, // TAG,
|
||||
Tag_UnitVehicle = 20, // TAG,
|
||||
FEntityPosition = 112,
|
||||
FEntityLocalMatrix = 113,
|
||||
FEntityWorldMatrix = 114,
|
||||
CActor = 115, // INDIRECT,
|
||||
FVendor_C = 117, // UPDATEABLE,
|
||||
FMirroredObject_C = 119,
|
||||
End = 255,
|
||||
};
|
||||
|
||||
inline constexpr bool IsUpdateableFragment(EntityFragment frag)
|
||||
{
|
||||
return frag == EntityFragment::CGObject || frag == EntityFragment::FVendor_C;
|
||||
}
|
||||
|
||||
inline constexpr bool IsIndirectFragment(EntityFragment frag)
|
||||
{
|
||||
return frag == EntityFragment::CGObject || frag == EntityFragment::CActor;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
struct EntityFragmentsHolder
|
||||
{
|
||||
std::array<EntityFragment, 8> Ids =
|
||||
{
|
||||
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, 2> UpdateableIds = { EntityFragment::End, EntityFragment::End };
|
||||
std::array<uint8, 2> UpdateableMasks = { };
|
||||
uint8 UpdateableCount = 0;
|
||||
uint8 ContentsChangedMask = CGObjectActiveMask;
|
||||
|
||||
void Add(EntityFragment fragment, bool update);
|
||||
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
|
||||
{
|
||||
Full = 0,
|
||||
Partial = 1
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TRINITYCORE_WOWCS_ENTITY_DEFINITIONS_H
|
||||
@@ -162,6 +162,8 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this)
|
||||
m_objectType |= TYPEMASK_PLAYER;
|
||||
m_objectTypeId = TYPEID_PLAYER;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Player, false);
|
||||
|
||||
m_session = session;
|
||||
|
||||
m_modMeleeHitChance = 7.5f;
|
||||
@@ -3712,6 +3714,7 @@ void Player::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
@@ -6343,8 +6346,8 @@ void Player::CheckAreaExplore()
|
||||
uint32 offset = areaEntry->AreaBit / PLAYER_EXPLORED_ZONES_BITS;
|
||||
uint64 val = UI64LIT(1) << (areaEntry->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
|
||||
|
||||
if (offset >= m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size()
|
||||
|| !(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][offset] & val))
|
||||
if (offset >= m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values.size()
|
||||
|| !(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[offset] & val))
|
||||
{
|
||||
AddExploredZones(offset, val);
|
||||
|
||||
@@ -6400,7 +6403,7 @@ void Player::AddExploredZones(uint32 pos, uint64 mask)
|
||||
.ModifyValue(&Player::m_activePlayerData)
|
||||
.ModifyValue(&UF::ActivePlayerData::BitVectors)
|
||||
.ModifyValue(&UF::BitVectors::Values, PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX)
|
||||
.ModifyValue(pos), mask);
|
||||
.ModifyValue(&UF::BitVector::Values, pos), mask);
|
||||
}
|
||||
|
||||
void Player::RemoveExploredZones(uint32 pos, uint64 mask)
|
||||
@@ -6409,7 +6412,7 @@ void Player::RemoveExploredZones(uint32 pos, uint64 mask)
|
||||
.ModifyValue(&Player::m_activePlayerData)
|
||||
.ModifyValue(&UF::ActivePlayerData::BitVectors)
|
||||
.ModifyValue(&UF::BitVectors::Values, PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX)
|
||||
.ModifyValue(pos), mask);
|
||||
.ModifyValue(&UF::BitVector::Values, pos), mask);
|
||||
}
|
||||
|
||||
bool Player::HasExploredZone(uint32 areaId) const
|
||||
@@ -6422,11 +6425,11 @@ bool Player::HasExploredZone(uint32 areaId) const
|
||||
return false;
|
||||
|
||||
size_t playerIndexOffset = size_t(area->AreaBit) / PLAYER_EXPLORED_ZONES_BITS;
|
||||
if (playerIndexOffset >= m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size())
|
||||
if (playerIndexOffset >= m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values.size())
|
||||
return false;
|
||||
|
||||
uint64 mask = uint64(1) << (area->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
|
||||
return (m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][playerIndexOffset] & mask) != 0;
|
||||
return (m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[playerIndexOffset] & mask) != 0;
|
||||
}
|
||||
|
||||
void Player::UpdateZoneAndAreaId()
|
||||
@@ -20157,10 +20160,10 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
|
||||
stmt->setUInt32(index++, GetLootSpecId());
|
||||
|
||||
ss.str("");
|
||||
for (size_t i = 0; i < m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size(); ++i)
|
||||
for (size_t i = 0; i < m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values.size(); ++i)
|
||||
{
|
||||
ss << uint32(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32((m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] >> 32) & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[i] & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32((m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[i] >> 32) & 0xFFFFFFFF) << ' ';
|
||||
}
|
||||
stmt->setString(index++, ss.str());
|
||||
|
||||
@@ -20317,10 +20320,10 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
|
||||
stmt->setUInt32(index++, GetLootSpecId());
|
||||
|
||||
ss.str("");
|
||||
for (size_t i = 0; i < m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size(); ++i)
|
||||
for (size_t i = 0; i < m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values.size(); ++i)
|
||||
{
|
||||
ss << uint32(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32((m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] >> 32) & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32(m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[i] & 0xFFFFFFFF) << ' ';
|
||||
ss << uint32((m_activePlayerData->BitVectors->Values[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].Values[i] >> 32) & 0xFFFFFFFF) << ' ';
|
||||
}
|
||||
stmt->setString(index++, ss.str());
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ enum PlayerSkillsConstants
|
||||
|
||||
enum PlayerDataFlagConstants
|
||||
{
|
||||
PLAYER_EXPLORED_ZONES_BITS = UF::size_of_value_type<decltype(UF::BitVectors::Values)::value_type>() * 8,
|
||||
PLAYER_EXPLORED_ZONES_BITS = UF::size_of_value_type<decltype(UF::BitVector::Values)>() * 8,
|
||||
|
||||
PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX = 1,
|
||||
PLAYER_DATA_FLAG_CHARACTER_DATA_INDEX = 2,
|
||||
@@ -2952,8 +2952,8 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
|
||||
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
UF::UpdateField<UF::PlayerData, 0, TYPEID_PLAYER> m_playerData;
|
||||
UF::UpdateField<UF::ActivePlayerData, 0, TYPEID_ACTIVE_PLAYER> m_activePlayerData;
|
||||
UF::UpdateField<UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER> m_playerData;
|
||||
UF::UpdateField<UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER> m_activePlayerData;
|
||||
|
||||
void SetAreaSpiritHealer(Creature* creature);
|
||||
ObjectGuid const& GetSpiritHealerGUID() const { return _areaSpiritHealerGUID; }
|
||||
|
||||
@@ -33,6 +33,8 @@ SceneObject::SceneObject() : WorldObject(false)
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.SceneObject = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_SceneObject, false);
|
||||
}
|
||||
|
||||
SceneObject::~SceneObject() = default;
|
||||
@@ -156,6 +158,7 @@ void SceneObject::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags,
|
||||
void SceneObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
|
||||
UF::SceneObjectData::Mask const& requestedSceneObjectMask, Player const* target) const
|
||||
{
|
||||
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask;
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set(TYPEID_OBJECT);
|
||||
@@ -166,6 +169,7 @@ void SceneObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::Objec
|
||||
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
|
||||
std::size_t sizePos = buffer.wpos();
|
||||
buffer << uint32(0);
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
|
||||
buffer << uint32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[TYPEID_OBJECT])
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
|
||||
void SetCreatedBySpellCast(ObjectGuid castId) { _createdBySpellCast = castId; }
|
||||
|
||||
UF::UpdateField<UF::SceneObjectData, 0, TYPEID_SCENEOBJECT> m_sceneObjectData;
|
||||
UF::UpdateField<UF::SceneObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_SCENEOBJECT> m_sceneObjectData;
|
||||
|
||||
private:
|
||||
bool ShouldBeRemoved() const;
|
||||
|
||||
@@ -92,6 +92,7 @@ Transport::Transport() : GameObject(),
|
||||
m_updateFlag.ServerTime = true;
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.Rotation = true;
|
||||
m_updateFlag.GameObject = true;
|
||||
}
|
||||
|
||||
Transport::~Transport()
|
||||
@@ -140,7 +141,6 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float
|
||||
}
|
||||
|
||||
_pathProgress = !goinfo->moTransport.allowstopping ? getMSTime() /*might be called before world update loop begins, don't use GameTime*/ % tInfo->TotalPathTime : 0;
|
||||
SetPathProgressForClient(float(_pathProgress) / float(tInfo->TotalPathTime));
|
||||
SetObjectScale(goinfo->size);
|
||||
SetPeriod(tInfo->TotalPathTime);
|
||||
SetEntry(goinfo->entry);
|
||||
@@ -203,8 +203,6 @@ void Transport::Update(uint32 diff)
|
||||
_eventsToTrigger->set();
|
||||
}
|
||||
|
||||
SetPathProgressForClient(float(_pathProgress) / float(GetTransportPeriod()));
|
||||
|
||||
uint32 timer = _pathProgress % GetTransportPeriod();
|
||||
|
||||
size_t eventToTriggerIndex = _eventsToTrigger->find_first();
|
||||
|
||||
@@ -89,6 +89,8 @@ class TC_GAME_API Transport final : public GameObject, public TransportBase
|
||||
uint32 GetTransportPeriod() const { return m_gameObjectData->Level; }
|
||||
void SetPeriod(uint32 period) { SetLevel(period); }
|
||||
uint32 GetTimer() const { return _pathProgress; }
|
||||
bool IsStopRequested() const { return _requestStopTimestamp.has_value(); }
|
||||
bool IsStopped() const { return HasDynamicFlag(GO_DYNFLAG_LO_STOPPED); }
|
||||
|
||||
void UpdatePosition(float x, float y, float z, float o);
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ Unit::Unit(bool isWorldObject) :
|
||||
|
||||
m_updateFlag.MovementUpdate = true;
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::Tag_Unit, false);
|
||||
|
||||
m_baseAttackSpeed = { };
|
||||
m_attackTimer = { };
|
||||
m_modAttackSpeedPct.fill(1.0f);
|
||||
|
||||
@@ -1836,7 +1836,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
UF::UpdateField<UF::UnitData, 0, TYPEID_UNIT> m_unitData;
|
||||
UF::UpdateField<UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT> m_unitData;
|
||||
|
||||
protected:
|
||||
explicit Unit (bool isWorldObject);
|
||||
|
||||
@@ -353,6 +353,9 @@ enum NPCFlags : uint32
|
||||
|
||||
DEFINE_ENUM_FLAG(NPCFlags);
|
||||
|
||||
inline constexpr NPCFlags UNIT_NPC_FLAG_VENDOR_MASK = UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_VENDOR_AMMO | UNIT_NPC_FLAG_VENDOR_FOOD
|
||||
| UNIT_NPC_FLAG_VENDOR_POISON | UNIT_NPC_FLAG_VENDOR_REAGENT;
|
||||
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum NPCFlags2 : uint32
|
||||
{
|
||||
|
||||
@@ -2069,12 +2069,14 @@ public:
|
||||
|
||||
if (owner->HasAchieved(ACHIEVEMENT_PONY_UP) && !me->HasAura(SPELL_AURA_TIRED_S) && !me->HasAura(SPELL_AURA_TIRED_G))
|
||||
{
|
||||
me->SetNpcFlag(UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_MAILBOX | UNIT_NPC_FLAG_VENDOR);
|
||||
me->SetVendor(UNIT_NPC_FLAG_VENDOR, true);
|
||||
me->SetNpcFlag(UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_MAILBOX);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_MAILBOX | UNIT_NPC_FLAG_VENDOR);
|
||||
me->SetVendor(UNIT_NPC_FLAG_VENDOR_MASK, false);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_MAILBOX);
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
|
||||
@@ -2083,7 +2085,8 @@ public:
|
||||
{
|
||||
case GOSSIP_OPTION_BANK:
|
||||
{
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_MAILBOX | UNIT_NPC_FLAG_VENDOR);
|
||||
me->SetVendor(UNIT_NPC_FLAG_VENDOR_MASK, false);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_MAILBOX);
|
||||
uint32 _bankAura = IsArgentSquire() ? SPELL_AURA_BANK_S : SPELL_AURA_BANK_G;
|
||||
if (!me->HasAura(_bankAura))
|
||||
DoCastSelf(_bankAura);
|
||||
@@ -2105,7 +2108,8 @@ public:
|
||||
}
|
||||
case GOSSIP_OPTION_MAIL:
|
||||
{
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_VENDOR);
|
||||
me->SetVendor(UNIT_NPC_FLAG_VENDOR_MASK, false);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_BANKER);
|
||||
uint32 _mailAura = IsArgentSquire() ? SPELL_AURA_POSTMAN_S : SPELL_AURA_POSTMAN_G;
|
||||
if (!me->HasAura(_mailAura))
|
||||
DoCastSelf(_mailAura);
|
||||
|
||||
Reference in New Issue
Block a user