/*
* 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 .
*/
#ifndef TRINITYCORE_BASE_ENTITY_H
#define TRINITYCORE_BASE_ENTITY_H
#include "Common.h"
#include "ObjectGuid.h"
#include "UpdateFields.h"
#include "WowCSEntityDefinitions.h"
#include
class BaseEntity;
class Player;
class UpdateData;
class WorldPacket;
typedef std::unordered_map UpdateDataMapType;
struct CreateObjectBits
{
bool HasEntityPosition : 1;
bool NoBirthAnim : 1;
bool EnablePortals : 1;
bool PlayHoverAnim : 1;
bool ThisIsYou : 1;
bool MovementUpdate : 1;
bool MovementTransport : 1;
bool Stationary : 1;
bool CombatVictim : 1;
bool ServerTime : 1;
bool Vehicle : 1;
bool AnimKit : 1;
bool Rotation : 1;
bool GameObject : 1;
bool SmoothPhasing : 1;
bool SceneObject : 1;
bool ActivePlayer : 1;
bool Conversation : 1;
bool Room : 1;
bool Decor : 1;
bool MeshObject : 1;
void Clear()
{
memset(this, 0, sizeof(CreateObjectBits));
}
};
namespace UF
{
class UpdateFieldHolder
{
public:
template
inline MutableFieldReference ModifyValue(UpdateField(Derived::* field));
template
inline OptionalUpdateFieldSetter ModifyValue(OptionalUpdateField(Derived::* field));
template
inline MutableFieldReference ModifyValue(OptionalUpdateField(Derived::* field), uint32 /*dummy*/);
template
inline void ClearChangesMask(UpdateField(Derived::* field));
template
inline void ClearChangesMask(OptionalUpdateField(Derived::* field));
uint32 GetChangedObjectTypeMask() const { return _changesMask; }
bool HasChanged(uint32 index) const { return (_changesMask & UpdateMaskHelpers::GetBlockFlag(index)) != 0; }
inline BaseEntity* GetOwner();
private:
friend BaseEntity;
// This class is tightly tied to BaseEntity::m_values member, do not construct elsewhere
UpdateFieldHolder() = default;
uint32 _changesMask = 0; // changes mask for data of Object subclasses
};
template
inline bool SetUpdateFieldValue(UpdateFieldPrivateSetter& setter, typename UpdateFieldPrivateSetter::value_type&& value)
{
return setter.SetValue(std::move(value));
}
template
inline typename DynamicUpdateFieldSetter::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter)
{
return setter.AddValue();
}
template
inline typename DynamicUpdateFieldSetter::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter, uint32 index)
{
return setter.InsertValue(index);
}
template
inline void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter, uint32 index)
{
setter.RemoveValue(index);
}
template
inline void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter& setter)
{
setter.Clear();
}
template
inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter& setter, std::type_identity_t const& key)
{
setter.RemoveKey(key);
}
template
inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter& setter)
{
setter.RemoveValue();
}
}
class TC_GAME_API BaseEntity
{
ObjectGuid m_guid;
public:
virtual ~BaseEntity();
bool IsInWorld() const { return m_inWorld; }
virtual void AddToWorld();
virtual void RemoveFromWorld();
static ObjectGuid GetGUID(BaseEntity const* o) { return o ? o->GetGUID() : ObjectGuid::Empty; }
ObjectGuid const& GetGUID() const { return m_guid; }
TypeID GetTypeId() const { return m_objectTypeId; }
bool isType(TypeMask mask) const { return (ObjectTypeMask[m_objectTypeId] & mask) != 0; }
inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); }
inline bool IsItem() const { return isType(TYPEMASK_ITEM); }
inline bool IsUnit() const { return isType(TYPEMASK_UNIT); }
inline bool IsCreature() const { return GetTypeId() == TYPEID_UNIT; }
inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; }
inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; }
inline bool IsDynObject() const { return GetTypeId() == TYPEID_DYNAMICOBJECT; }
inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; }
inline bool IsAreaTrigger() const { return GetTypeId() == TYPEID_AREATRIGGER; }
inline bool IsSceneObject() const { return GetTypeId() == TYPEID_SCENEOBJECT; }
inline bool IsConversation() const { return GetTypeId() == TYPEID_CONVERSATION; }
inline bool IsMeshObject() const { return GetTypeId() == TYPEID_MESH_OBJECT; }
virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
void SendUpdateToPlayer(Player* player) const;
void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const;
void BuildDestroyUpdateBlock(UpdateData* data) const;
void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
virtual void DestroyForPlayer(Player const* target) const;
void SendOutOfRangeForPlayer(Player const* target) const;
virtual void ClearUpdateMask(bool remove);
virtual std::string GetNameForLocaleIdx(LocaleConstant locale) const = 0;
void SetIsNewObject(bool enable) { m_isNewObject = enable; }
bool IsDestroyedObject() const { return m_isDestroyedObject; }
void SetDestroyedObject(bool destroyed) { m_isDestroyedObject = destroyed; }
virtual void BuildUpdate([[maybe_unused]] UpdateDataMapType& data_map) { }
void BuildUpdateChangesMask();
void BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const;
friend UF::UpdateFieldHolder;
UF::UpdateFieldHolder m_values;
template
void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter const& /*setter*/)
{
AddToObjectUpdateIfNeeded();
}
virtual std::string GetDebugInfo() const;
protected:
BaseEntity();
void _Create(ObjectGuid const& guid) { m_guid = guid; }
template
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter setter, typename UF::UpdateFieldPrivateSetter::value_type value)
{
if (UF::SetUpdateFieldValue(setter, std::move(value)))
AddToObjectUpdateIfNeeded();
}
template
void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter setter, typename UF::UpdateFieldPrivateSetter::value_type flag)
{
static_assert(std::is_integral_v, "SetUpdateFieldFlagValue must be used with integral types");
this->SetUpdateFieldValue(setter, setter.GetValue() | flag);
}
template
void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter setter, typename UF::UpdateFieldPrivateSetter::value_type flag)
{
static_assert(std::is_integral_v, "RemoveUpdateFieldFlagValue must be used with integral types");
this->SetUpdateFieldValue(setter, setter.GetValue() & ~flag);
}
template
typename UF::DynamicUpdateFieldSetter::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter setter)
{
AddToObjectUpdateIfNeeded();
return UF::AddDynamicUpdateFieldValue(setter);
}
template
typename UF::DynamicUpdateFieldSetter::insert_result InsertDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter setter, uint32 index)
{
AddToObjectUpdateIfNeeded();
return UF::InsertDynamicUpdateFieldValue(setter, index);
}
template
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter setter, uint32 index)
{
AddToObjectUpdateIfNeeded();
UF::RemoveDynamicUpdateFieldValue(setter, index);
}
template
void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter setter, std::type_identity_t const& key)
{
AddToObjectUpdateIfNeeded();
UF::RemoveMapUpdateFieldValue(setter, key);
}
template
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter setter)
{
AddToObjectUpdateIfNeeded();
UF::ClearDynamicUpdateFieldValues(setter);
}
template
void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter setter)
{
AddToObjectUpdateIfNeeded();
UF::RemoveOptionalUpdateFieldValue(setter);
}
// stat system helpers
template
void SetUpdateFieldStatValue(UF::UpdateFieldPrivateSetter setter, typename UF::UpdateFieldPrivateSetter::value_type value)
{
static_assert(std::is_arithmetic_v, "SetUpdateFieldStatValue must be used with arithmetic types");
this->SetUpdateFieldValue(setter, std::max(value, T(0)));
}
template
void ApplyModUpdateFieldValue(UF::UpdateFieldPrivateSetter setter, typename UF::UpdateFieldPrivateSetter::value_type mod, bool apply)
{
static_assert(std::is_arithmetic_v, "SetUpdateFieldStatValue must be used with arithmetic types");
T value = setter.GetValue();
if (apply)
value += mod;
else
value -= mod;
this->SetUpdateFieldValue(setter, value);
}
template
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter setter, float percent, bool apply)
{
static_assert(std::is_arithmetic_v, "SetUpdateFieldStatValue must be used with arithmetic types");
T value = setter.GetValue();
// don't want to include Util.h here
//ApplyPercentModFloatVar(value, percent, apply);
if (percent == -100.0f)
percent = -99.99f;
value *= (apply ? (100.0f + percent) / 100.0f : 100.0f / (100.0f + percent));
this->SetUpdateFieldValue(setter, value);
}
template
void DoWithSuppressingObjectUpdates(Action&& action)
{
bool wasUpdatedBeforeAction = m_objectUpdated;
action();
if (m_objectUpdated && !wasUpdatedBeforeAction)
{
RemoveFromObjectUpdate();
m_objectUpdated = false;
}
}
void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const;
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const;
static void BuildEntityFragments(ByteBuffer* data, std::span fragments);
TypeID m_objectTypeId = static_cast(NUM_CLIENT_OBJECT_TYPES);
CreateObjectBits m_updateFlag = {};
WowCS::EntityFragmentsHolder m_entityFragments;
virtual bool AddToObjectUpdate() = 0;
virtual void RemoveFromObjectUpdate() = 0;
void AddToObjectUpdateIfNeeded();
bool m_objectUpdated = false;
private:
bool m_inWorld = false;
bool m_isNewObject = false;
bool m_isDestroyedObject = false;
BaseEntity(BaseEntity const& right) = delete;
BaseEntity(BaseEntity&& right) = delete;
BaseEntity& operator=(BaseEntity const& right) = delete;
BaseEntity& operator=(BaseEntity&& right) = delete;
};
inline BaseEntity* UF::UpdateFieldHolder::GetOwner()
{
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
return reinterpret_cast(reinterpret_cast(this) - offsetof(BaseEntity, m_values));
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
#pragma GCC diagnostic pop
#endif
}
template
inline UF::MutableFieldReference UF::UpdateFieldHolder::ModifyValue(UpdateField Derived::* field)
{
BaseEntity* owner = GetOwner();
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
return { (static_cast(owner)->*field)._value };
}
template
inline UF::OptionalUpdateFieldSetter UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField Derived::* field)
{
BaseEntity* owner = GetOwner();
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
return { static_cast(owner)->*field };
}
template
inline UF::MutableFieldReference UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField Derived::* field, uint32 /*dummy*/)
{
BaseEntity* owner = GetOwner();
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
auto& uf = (static_cast(owner)->*field);
if (!uf.has_value())
uf.ConstructValue();
return { *uf._value };
}
template
inline void UF::UpdateFieldHolder::ClearChangesMask(UpdateField Derived::* field)
{
BaseEntity* owner = GetOwner();
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
(static_cast(owner)->*field)._value.ClearChangesMask();
}
template
inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField Derived::* field)
{
BaseEntity* owner = GetOwner();
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
auto& uf = (static_cast(owner)->*field);
if (uf.has_value())
uf._value->ClearChangesMask();
}
#endif // TRINITYCORE_BASE_ENTITY_H