Core/Objects: Create a base class for Object to support creating new client visible object types
This commit is contained in:
@@ -138,7 +138,7 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti
|
||||
|
||||
_areaTriggerTemplate = _areaTriggerCreateProperties->Template;
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
|
||||
_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
|
||||
|
||||
if (GetTemplate())
|
||||
SetEntry(GetTemplate()->Id.Id);
|
||||
|
||||
@@ -176,7 +176,7 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry,
|
||||
Relocate(pos);
|
||||
RelocateStationaryPosition(pos);
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
|
||||
_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
|
||||
PhasingHandler::InheritPhaseShift(this, creator);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
@@ -65,7 +65,7 @@ void Corpse::RemoveFromWorld()
|
||||
|
||||
bool Corpse::Create(ObjectGuid::LowType guidlow, Map* map)
|
||||
{
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(map->GetId(), 0, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Corpse>(map->GetId(), 0, guidlow));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner)
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(owner->GetMapId(), 0, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Corpse>(owner->GetMapId(), 0, guidlow));
|
||||
|
||||
SetObjectScale(1.0f);
|
||||
SetOwnerGUID(owner->GetGUID());
|
||||
@@ -190,7 +190,7 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields)
|
||||
float o = fields[3].GetFloat();
|
||||
uint32 mapId = fields[4].GetUInt16();
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Corpse>(mapId, 0, guid));
|
||||
_Create(ObjectGuid::Create<HighGuid::Corpse>(mapId, 0, guid));
|
||||
|
||||
SetObjectScale(1.0f);
|
||||
SetDisplayId(fields[5].GetUInt32());
|
||||
|
||||
@@ -1829,9 +1829,9 @@ bool Creature::CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, Creatu
|
||||
SetOriginalEntry(entry);
|
||||
|
||||
if (vehId || cinfo->VehicleId)
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Vehicle>(GetMapId(), entry, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Vehicle>(GetMapId(), entry, guidlow));
|
||||
else
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Creature>(GetMapId(), entry, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Creature>(GetMapId(), entry, guidlow));
|
||||
|
||||
if (!UpdateEntry(entry, data))
|
||||
return false;
|
||||
|
||||
@@ -92,7 +92,7 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldObject::_Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow));
|
||||
PhasingHandler::InheritPhaseShift(this, caster);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
@@ -1023,7 +1023,7 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
|
||||
m_updateFlag.ServerTime = true;
|
||||
}
|
||||
|
||||
Object::_Create(guid);
|
||||
_Create(guid);
|
||||
|
||||
m_goInfo = goInfo;
|
||||
m_goTemplateAddon = sObjectMgr->GetGameObjectTemplateAddon(entry);
|
||||
|
||||
@@ -75,7 +75,7 @@ bool Bag::Create(ObjectGuid::LowType guidlow, uint32 itemid, ItemContext context
|
||||
if (!itemProto || itemProto->GetContainerSlots() > MAX_BAG_SIZE)
|
||||
return false;
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
|
||||
|
||||
_bonusData.Initialize(itemProto);
|
||||
|
||||
|
||||
@@ -506,7 +506,7 @@ Item::~Item() = default;
|
||||
|
||||
bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext context, Player const* owner)
|
||||
{
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
|
||||
|
||||
SetEntry(itemId);
|
||||
SetObjectScale(1.0f);
|
||||
@@ -922,7 +922,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
|
||||
|
||||
// create item before any checks for store correct guid
|
||||
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Item>(guid));
|
||||
_Create(ObjectGuid::Create<HighGuid::Item>(guid));
|
||||
|
||||
// Set entry, MUST be before proto check
|
||||
SetEntry(entry);
|
||||
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "Conversation.h"
|
||||
#include "DB2Structure.h"
|
||||
#include "Errors.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "MovementPackets.h"
|
||||
#include "Player.h"
|
||||
#include "SmoothPhasing.h"
|
||||
#include "Transport.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
BaseEntity::BaseEntity() = default;
|
||||
|
||||
BaseEntity::~BaseEntity()
|
||||
{
|
||||
if (IsInWorld())
|
||||
{
|
||||
TC_LOG_FATAL("misc", "BaseEntity::~BaseEntity {} deleted but still in world!!", GetGUID());
|
||||
ABORT();
|
||||
}
|
||||
|
||||
if (m_objectUpdated)
|
||||
{
|
||||
TC_LOG_FATAL("misc", "BaseEntity::~BaseEntity {} deleted but still in update list!!", GetGUID());
|
||||
ABORT();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseEntity::AddToWorld()
|
||||
{
|
||||
if (m_inWorld)
|
||||
return;
|
||||
|
||||
m_inWorld = true;
|
||||
|
||||
// synchronize values mirror with values array (changes will send in updatecreate opcode any way
|
||||
ASSERT(!m_objectUpdated);
|
||||
ClearUpdateMask(false);
|
||||
}
|
||||
|
||||
void BaseEntity::RemoveFromWorld()
|
||||
{
|
||||
if (!m_inWorld)
|
||||
return;
|
||||
|
||||
m_inWorld = false;
|
||||
|
||||
// if we remove from world then sending changes not required
|
||||
ClearUpdateMask(true);
|
||||
}
|
||||
|
||||
void BaseEntity::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
uint8 updateType = m_isNewObject ? UPDATETYPE_CREATE_OBJECT2 : UPDATETYPE_CREATE_OBJECT;
|
||||
uint8 objectType = m_objectTypeId;
|
||||
CreateObjectBits flags = m_updateFlag;
|
||||
|
||||
if (target == this) // building packet for yourself
|
||||
{
|
||||
flags.ThisIsYou = true;
|
||||
flags.ActivePlayer = true;
|
||||
objectType = TYPEID_ACTIVE_PLAYER;
|
||||
}
|
||||
|
||||
if (IsWorldObject())
|
||||
{
|
||||
WorldObject const* worldObject = static_cast<WorldObject const*>(this);
|
||||
if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
|
||||
flags.SmoothPhasing = true;
|
||||
}
|
||||
|
||||
ByteBuffer& buf = data->GetBuffer();
|
||||
buf << uint8(updateType);
|
||||
buf << GetGUID();
|
||||
buf << uint8(objectType);
|
||||
|
||||
BuildMovementUpdate(&buf, flags, target);
|
||||
|
||||
UF::UpdateFieldFlag fieldFlags = GetUpdateFieldFlagsFor(target);
|
||||
std::size_t sizePos = buf.wpos();
|
||||
buf << uint32(0);
|
||||
buf << uint8(fieldFlags);
|
||||
BuildEntityFragments(&buf, m_entityFragments.GetIds());
|
||||
buf << uint8(1); // IndirectFragmentActive: CGObject
|
||||
BuildValuesCreate(&buf, fieldFlags, target);
|
||||
buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
|
||||
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void BaseEntity::SendUpdateToPlayer(Player* player) const
|
||||
{
|
||||
// send create update to player
|
||||
UpdateData upd(player->GetMapId());
|
||||
WorldPacket packet;
|
||||
|
||||
if (player->HaveAtClient(this))
|
||||
BuildValuesUpdateBlockForPlayer(&upd, player);
|
||||
else
|
||||
BuildCreateUpdateBlockForPlayer(&upd, player);
|
||||
upd.BuildPacket(&packet);
|
||||
player->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void BaseEntity::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const
|
||||
{
|
||||
ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
|
||||
|
||||
EnumFlag<UF::UpdateFieldFlag> fieldFlags = GetUpdateFieldFlagsFor(target);
|
||||
std::size_t sizePos = buf.wpos();
|
||||
buf << uint32(0);
|
||||
buf << uint8(fieldFlags.HasFlag(UF::UpdateFieldFlag::Owner));
|
||||
buf << uint8(m_entityFragments.IdsChanged);
|
||||
if (m_entityFragments.IdsChanged)
|
||||
{
|
||||
buf << uint8(WowCS::EntityFragmentSerializationType::Full);
|
||||
BuildEntityFragments(&buf, m_entityFragments.GetIds());
|
||||
}
|
||||
buf << uint8(m_entityFragments.ContentsChangedMask);
|
||||
|
||||
BuildValuesUpdate(&buf, fieldFlags, target);
|
||||
buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
|
||||
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void BaseEntity::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
|
||||
{
|
||||
data->append(fragments.data(), fragments.size());
|
||||
*data << uint8(WowCS::EntityFragment::End);
|
||||
}
|
||||
|
||||
void BaseEntity::BuildDestroyUpdateBlock(UpdateData* data) const
|
||||
{
|
||||
data->AddDestroyObject(GetGUID());
|
||||
}
|
||||
|
||||
void BaseEntity::BuildOutOfRangeUpdateBlock(UpdateData* data) const
|
||||
{
|
||||
data->AddOutOfRangeGUID(GetGUID());
|
||||
}
|
||||
|
||||
ByteBuffer& BaseEntity::PrepareValuesUpdateBuffer(UpdateData* data) const
|
||||
{
|
||||
ByteBuffer& buffer = data->GetBuffer();
|
||||
buffer << uint8(UPDATETYPE_VALUES);
|
||||
buffer << GetGUID();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void BaseEntity::DestroyForPlayer(Player const* target) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
UpdateData updateData(target->GetMapId());
|
||||
BuildDestroyUpdateBlock(&updateData);
|
||||
WorldPacket packet;
|
||||
updateData.BuildPacket(&packet);
|
||||
target->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void BaseEntity::SendOutOfRangeForPlayer(Player const* target) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
UpdateData updateData(target->GetMapId());
|
||||
BuildOutOfRangeUpdateBlock(&updateData);
|
||||
WorldPacket packet;
|
||||
updateData.BuildPacket(&packet);
|
||||
target->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void BaseEntity::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const
|
||||
{
|
||||
std::span<uint32 const> PauseTimes;
|
||||
if (IsGameObject())
|
||||
PauseTimes = static_cast<GameObject const*>(this)->GetPauseTimes();
|
||||
|
||||
data->WriteBit(IsWorldObject()); // HasPositionFragment
|
||||
data->WriteBit(flags.NoBirthAnim);
|
||||
data->WriteBit(flags.EnablePortals);
|
||||
data->WriteBit(flags.PlayHoverAnim);
|
||||
data->WriteBit(flags.ThisIsYou);
|
||||
data->WriteBit(flags.MovementUpdate);
|
||||
data->WriteBit(flags.MovementTransport);
|
||||
data->WriteBit(flags.Stationary);
|
||||
data->WriteBit(flags.CombatVictim);
|
||||
data->WriteBit(flags.ServerTime);
|
||||
data->WriteBit(flags.Vehicle);
|
||||
data->WriteBit(flags.AnimKit);
|
||||
data->WriteBit(flags.Rotation);
|
||||
data->WriteBit(flags.GameObject);
|
||||
data->WriteBit(flags.SmoothPhasing);
|
||||
data->WriteBit(flags.SceneObject);
|
||||
data->WriteBit(flags.ActivePlayer);
|
||||
data->WriteBit(flags.Conversation);
|
||||
data->WriteBit(flags.Room);
|
||||
data->WriteBit(flags.Decor);
|
||||
data->WriteBit(flags.MeshObject);
|
||||
data->FlushBits();
|
||||
|
||||
if (flags.MovementUpdate)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||
bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
|
||||
bool HasSpline = unit->IsSplineEnabled();
|
||||
bool HasInertia = unit->m_movementInfo.inertia.has_value();
|
||||
bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value();
|
||||
bool HasDriveStatus = unit->m_movementInfo.driveStatus.has_value();
|
||||
bool HasStandingOnGameObjectGUID = unit->m_movementInfo.standingOnGameObjectGUID.has_value();
|
||||
|
||||
*data << GetGUID(); // MoverGUID
|
||||
|
||||
*data << uint32(unit->GetUnitMovementFlags());
|
||||
*data << uint32(unit->GetExtraUnitMovementFlags());
|
||||
*data << uint32(unit->GetExtraUnitMovementFlags2());
|
||||
|
||||
*data << uint32(unit->m_movementInfo.time); // MoveTime
|
||||
*data << float(unit->GetPositionX());
|
||||
*data << float(unit->GetPositionY());
|
||||
*data << float(unit->GetPositionZ());
|
||||
*data << float(unit->GetOrientation());
|
||||
|
||||
*data << float(unit->m_movementInfo.pitch); // Pitch
|
||||
*data << float(unit->m_movementInfo.stepUpStartElevation); // StepUpStartElevation
|
||||
|
||||
*data << uint32(0); // RemoveForcesIDs.size()
|
||||
*data << uint32(0); // MoveIndex
|
||||
|
||||
//for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
|
||||
// *data << ObjectGuid(RemoveForcesIDs);
|
||||
|
||||
data->WriteBit(HasStandingOnGameObjectGUID); // HasStandingOnGameObjectGUID
|
||||
data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
|
||||
data->WriteBit(HasFall); // HasFall
|
||||
data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
|
||||
data->WriteBit(false); // HeightChangeFailed
|
||||
data->WriteBit(false); // RemoteTimeValid
|
||||
data->WriteBit(HasInertia); // HasInertia
|
||||
data->WriteBit(HasAdvFlying); // HasAdvFlying
|
||||
data->WriteBit(HasDriveStatus); // HasDriveStatus
|
||||
data->FlushBits();
|
||||
|
||||
if (!unit->m_movementInfo.transport.guid.IsEmpty())
|
||||
*data << unit->m_movementInfo.transport;
|
||||
|
||||
if (HasStandingOnGameObjectGUID)
|
||||
*data << *unit->m_movementInfo.standingOnGameObjectGUID;
|
||||
|
||||
if (HasInertia)
|
||||
{
|
||||
*data << unit->m_movementInfo.inertia->id;
|
||||
*data << unit->m_movementInfo.inertia->force.PositionXYZStream();
|
||||
*data << uint32(unit->m_movementInfo.inertia->lifetime);
|
||||
}
|
||||
|
||||
if (HasAdvFlying)
|
||||
{
|
||||
*data << float(unit->m_movementInfo.advFlying->forwardVelocity);
|
||||
*data << float(unit->m_movementInfo.advFlying->upVelocity);
|
||||
}
|
||||
|
||||
if (HasFall)
|
||||
{
|
||||
*data << uint32(unit->m_movementInfo.jump.fallTime); // Time
|
||||
*data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
|
||||
|
||||
if (data->WriteBit(HasFallDirection))
|
||||
{
|
||||
*data << float(unit->m_movementInfo.jump.sinAngle); // Direction
|
||||
*data << float(unit->m_movementInfo.jump.cosAngle);
|
||||
*data << float(unit->m_movementInfo.jump.xyspeed); // Speed
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDriveStatus)
|
||||
{
|
||||
*data << float(unit->m_movementInfo.driveStatus->speed);
|
||||
*data << float(unit->m_movementInfo.driveStatus->movementAngle);
|
||||
data->WriteBit(unit->m_movementInfo.driveStatus->accelerating);
|
||||
data->WriteBit(unit->m_movementInfo.driveStatus->drifting);
|
||||
data->FlushBits();
|
||||
}
|
||||
|
||||
*data << float(unit->GetSpeed(MOVE_WALK));
|
||||
*data << float(unit->GetSpeed(MOVE_RUN));
|
||||
*data << float(unit->GetSpeed(MOVE_RUN_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_SWIM));
|
||||
*data << float(unit->GetSpeed(MOVE_SWIM_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_FLIGHT));
|
||||
*data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_TURN_RATE));
|
||||
*data << float(unit->GetSpeed(MOVE_PITCH_RATE));
|
||||
|
||||
if (MovementForces const* movementForces = unit->GetMovementForces())
|
||||
{
|
||||
*data << uint32(movementForces->GetForces()->size());
|
||||
*data << float(movementForces->GetModMagnitude()); // MovementForcesModMagnitude
|
||||
}
|
||||
else
|
||||
{
|
||||
*data << uint32(0);
|
||||
*data << float(1.0f); // MovementForcesModMagnitude
|
||||
}
|
||||
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_AIR_FRICTION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_MAX_VEL));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LIFT_COEFFICIENT));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_DOUBLE_JUMP_VEL_MOD));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_GLIDE_START_MIN_HEIGHT));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_ADD_IMPULSE_MAX_SPEED));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_BANKING_RATE));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_BANKING_RATE));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_DOWN));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_DOWN));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_UP));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_UP));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_SURFACE_FRICTION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_OVER_MAX_DECELERATION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LAUNCH_SPEED_COEFFICIENT));
|
||||
|
||||
data->WriteBit(HasSpline);
|
||||
data->FlushBits();
|
||||
|
||||
if (MovementForces const* movementForces = unit->GetMovementForces())
|
||||
for (MovementForce const& force : *movementForces->GetForces())
|
||||
WorldPackets::Movement::CommonMovement::WriteMovementForceWithDirection(force, *data, unit);
|
||||
|
||||
if (HasSpline)
|
||||
WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
|
||||
}
|
||||
|
||||
*data << uint32(PauseTimes.size());
|
||||
|
||||
if (flags.Stationary)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << self->GetStationaryPosition().PositionXYZOStream();
|
||||
}
|
||||
|
||||
if (flags.CombatVictim)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
*data << unit->GetVictim()->GetGUID(); // CombatVictim
|
||||
}
|
||||
|
||||
if (flags.ServerTime)
|
||||
*data << uint32(GameTime::GetGameTimeMS());
|
||||
|
||||
if (flags.Vehicle)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
*data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
|
||||
*data << float(unit->GetOrientation()); // InitialRawFacing
|
||||
}
|
||||
|
||||
if (flags.AnimKit)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << uint16(self->GetAIAnimKitId()); // AiID
|
||||
*data << uint16(self->GetMovementAnimKitId()); // MovementID
|
||||
*data << uint16(self->GetMeleeAnimKitId()); // MeleeID
|
||||
}
|
||||
|
||||
if (flags.Rotation)
|
||||
{
|
||||
GameObject const* gameObject = static_cast<GameObject const*>(this);
|
||||
*data << uint64(gameObject->GetPackedLocalRotation()); // Rotation
|
||||
}
|
||||
|
||||
//if (flags.Room)
|
||||
// *data << ObjectGuid(HouseGUID);
|
||||
|
||||
//if (flags.Decor)
|
||||
// *data << ObjectGuid(RoomGUID);
|
||||
|
||||
//if (flags.MeshObject)
|
||||
//{
|
||||
// *data << ObjectGuid(AttachParentGUID);
|
||||
// *data << TaggedPosition<Position::XYZ>(PositionLocalSpace);
|
||||
// *data << QuaternionData(RotationLocalSpace);
|
||||
// *data << float(ScaleLocalSpace);
|
||||
// *data << uint8(AttachmentFlags);
|
||||
//}
|
||||
|
||||
if (!PauseTimes.empty())
|
||||
data->append(PauseTimes.data(), PauseTimes.size());
|
||||
|
||||
if (flags.MovementTransport)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << self->m_movementInfo.transport;
|
||||
}
|
||||
|
||||
if (flags.GameObject)
|
||||
{
|
||||
GameObject const* gameObject = static_cast<GameObject const*>(this);
|
||||
|
||||
bool bit8 = false;
|
||||
bool isTransport = gameObject->GetGOInfo()->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT;
|
||||
|
||||
*data << uint32(gameObject->GetWorldEffectID());
|
||||
|
||||
data->WriteBit(bit8);
|
||||
data->WriteBit(isTransport);
|
||||
data->WriteBit(gameObject->GetPathProgressForClient().has_value());
|
||||
data->FlushBits();
|
||||
if (isTransport)
|
||||
{
|
||||
Transport const* transport = static_cast<Transport const*>(gameObject);
|
||||
uint32 period = transport->GetTransportPeriod();
|
||||
|
||||
*data << uint32((((int64(transport->GetTimer()) - int64(GameTime::GetGameTimeMS())) % period) + period) % period); // TimeOffset
|
||||
*data << uint32(transport->GetNextStopTimestamp().value_or(0));
|
||||
data->WriteBit(transport->GetNextStopTimestamp().has_value());
|
||||
data->WriteBit(transport->IsStopped());
|
||||
data->WriteBit(false);
|
||||
data->FlushBits();
|
||||
}
|
||||
|
||||
if (bit8)
|
||||
*data << uint32(0);
|
||||
|
||||
if (gameObject->GetPathProgressForClient())
|
||||
*data << float(*gameObject->GetPathProgressForClient());
|
||||
}
|
||||
|
||||
if (flags.SmoothPhasing)
|
||||
{
|
||||
SmoothPhasingInfo const* smoothPhasingInfo = static_cast<WorldObject const*>(this)->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID());
|
||||
ASSERT(smoothPhasingInfo);
|
||||
|
||||
data->WriteBit(smoothPhasingInfo->ReplaceActive);
|
||||
data->WriteBit(smoothPhasingInfo->StopAnimKits);
|
||||
data->WriteBit(smoothPhasingInfo->ReplaceObject.has_value());
|
||||
data->FlushBits();
|
||||
if (smoothPhasingInfo->ReplaceObject)
|
||||
*data << *smoothPhasingInfo->ReplaceObject;
|
||||
}
|
||||
|
||||
if (flags.SceneObject)
|
||||
{
|
||||
data->WriteBit(false); // HasLocalScriptData
|
||||
data->WriteBit(false); // HasPetBattleFullUpdate
|
||||
data->FlushBits();
|
||||
|
||||
// if (HasLocalScriptData)
|
||||
// {
|
||||
// data->WriteBits(Data.length(), 7);
|
||||
// data->FlushBits();
|
||||
// data->WriteString(Data);
|
||||
// }
|
||||
|
||||
// if (HasPetBattleFullUpdate)
|
||||
// {
|
||||
// for (std::size_t i = 0; i < 2; ++i)
|
||||
// {
|
||||
// *data << ObjectGuid(Players[i].CharacterID);
|
||||
// *data << int32(Players[i].TrapAbilityID);
|
||||
// *data << int32(Players[i].TrapStatus);
|
||||
// *data << uint16(Players[i].RoundTimeSecs);
|
||||
// *data << int8(Players[i].FrontPet);
|
||||
// *data << uint8(Players[i].InputFlags);
|
||||
|
||||
// data->WriteBits(Players[i].Pets.size(), 2);
|
||||
// data->FlushBits();
|
||||
// for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
|
||||
// {
|
||||
// *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
|
||||
// *data << int32(Players[i].Pets[j].SpeciesID);
|
||||
// *data << int32(Players[i].Pets[j].CreatureID);
|
||||
// *data << int32(Players[i].Pets[j].DisplayID);
|
||||
// *data << int16(Players[i].Pets[j].Level);
|
||||
// *data << int16(Players[i].Pets[j].Xp);
|
||||
// *data << int32(Players[i].Pets[j].CurHealth);
|
||||
// *data << int32(Players[i].Pets[j].MaxHealth);
|
||||
// *data << int32(Players[i].Pets[j].Power);
|
||||
// *data << int32(Players[i].Pets[j].Speed);
|
||||
// *data << int32(Players[i].Pets[j].NpcTeamMemberID);
|
||||
// *data << uint8(Players[i].Pets[j].BreedQuality);
|
||||
// *data << uint16(Players[i].Pets[j].StatusFlags);
|
||||
// *data << int8(Players[i].Pets[j].Slot);
|
||||
|
||||
// *data << uint32(Players[i].Pets[j].Abilities.size());
|
||||
// *data << uint32(Players[i].Pets[j].Auras.size());
|
||||
// *data << uint32(Players[i].Pets[j].States.size());
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
|
||||
// {
|
||||
// *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
|
||||
// *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
|
||||
// *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
|
||||
// *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
|
||||
// *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
|
||||
// }
|
||||
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
|
||||
// {
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
|
||||
// *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
|
||||
// *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
|
||||
// }
|
||||
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
|
||||
// {
|
||||
// *data << uint32(Players[i].Pets[j].States[k].StateID);
|
||||
// *data << int32(Players[i].Pets[j].States[k].StateValue);
|
||||
// }
|
||||
|
||||
// data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
|
||||
// data->FlushBits();
|
||||
// data->WriteString(Players[i].Pets[j].CustomName);
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (std::size_t i = 0; i < 3; ++i)
|
||||
// {
|
||||
// *data << uint32(Enviros[j].Auras.size());
|
||||
// *data << uint32(Enviros[j].States.size());
|
||||
// for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
|
||||
// {
|
||||
// *data << int32(Enviros[j].Auras[j].AbilityID);
|
||||
// *data << uint32(Enviros[j].Auras[j].InstanceID);
|
||||
// *data << int32(Enviros[j].Auras[j].RoundsRemaining);
|
||||
// *data << int32(Enviros[j].Auras[j].CurrentRound);
|
||||
// *data << uint8(Enviros[j].Auras[j].CasterPBOID);
|
||||
// }
|
||||
|
||||
// for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
|
||||
// {
|
||||
// *data << uint32(Enviros[i].States[j].StateID);
|
||||
// *data << int32(Enviros[i].States[j].StateValue);
|
||||
// }
|
||||
// }
|
||||
|
||||
// *data << uint16(WaitingForFrontPetsMaxSecs);
|
||||
// *data << uint16(PvpMaxRoundTime);
|
||||
// *data << int32(CurRound);
|
||||
// *data << uint32(NpcCreatureID);
|
||||
// *data << uint32(NpcDisplayID);
|
||||
// *data << int8(CurPetBattleState);
|
||||
// *data << uint8(ForfeitPenalty);
|
||||
// *data << ObjectGuid(InitialWildPetGUID);
|
||||
// data->WriteBit(IsPVP);
|
||||
// data->WriteBit(CanAwardXP);
|
||||
// data->FlushBits();
|
||||
// }
|
||||
}
|
||||
|
||||
if (flags.ActivePlayer)
|
||||
{
|
||||
Player const* player = static_cast<Player const*>(this);
|
||||
|
||||
bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty();
|
||||
bool HasRuneState = player->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
|
||||
|
||||
data->WriteBit(HasSceneInstanceIDs);
|
||||
data->WriteBit(HasRuneState);
|
||||
data->FlushBits();
|
||||
if (HasSceneInstanceIDs)
|
||||
{
|
||||
*data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size());
|
||||
for (auto const& [sceneInstanceId, _] : player->GetSceneMgr().GetSceneTemplateByInstanceMap())
|
||||
*data << uint32(sceneInstanceId);
|
||||
}
|
||||
if (HasRuneState)
|
||||
{
|
||||
float baseCd = float(player->GetRuneBaseCooldown());
|
||||
uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
|
||||
|
||||
*data << uint8((1 << maxRunes) - 1);
|
||||
*data << uint8(player->GetRunesState());
|
||||
*data << uint32(maxRunes);
|
||||
for (uint32 i = 0; i < maxRunes; ++i)
|
||||
*data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.Conversation)
|
||||
{
|
||||
Conversation const* self = static_cast<Conversation const*>(this);
|
||||
if (data->WriteBit(self->GetTextureKitId() != 0))
|
||||
*data << uint32(self->GetTextureKitId());
|
||||
|
||||
data->FlushBits();
|
||||
}
|
||||
}
|
||||
|
||||
UF::UpdateFieldFlag BaseEntity::GetUpdateFieldFlagsFor(Player const* /*target*/) const
|
||||
{
|
||||
return UF::UpdateFieldFlag::None;
|
||||
}
|
||||
|
||||
void BaseEntity::AddToObjectUpdateIfNeeded()
|
||||
{
|
||||
if (m_inWorld && !m_objectUpdated)
|
||||
m_objectUpdated = AddToObjectUpdate();
|
||||
}
|
||||
|
||||
void BaseEntity::ClearUpdateMask(bool remove)
|
||||
{
|
||||
m_entityFragments.IdsChanged = false;
|
||||
|
||||
if (m_objectUpdated)
|
||||
{
|
||||
if (remove)
|
||||
RemoveFromObjectUpdate();
|
||||
m_objectUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseEntity::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
|
||||
{
|
||||
UpdateDataMapType::iterator iter = data_map.try_emplace(player, player->GetMapId()).first;
|
||||
BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
|
||||
}
|
||||
|
||||
std::string BaseEntity::GetDebugInfo() const
|
||||
{
|
||||
return Trinity::StringFormat("{}", GetGUID());
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_BASE_ENTITY_H
|
||||
#define TRINITYCORE_BASE_ENTITY_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "UpdateFields.h"
|
||||
#include "WowCSEntityDefinitions.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class BaseEntity;
|
||||
class Player;
|
||||
class UpdateData;
|
||||
class WorldPacket;
|
||||
|
||||
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
|
||||
|
||||
struct CreateObjectBits
|
||||
{
|
||||
bool NoBirthAnim : 1;
|
||||
bool EnablePortals : 1;
|
||||
bool PlayHoverAnim : 1;
|
||||
bool MovementUpdate : 1;
|
||||
bool MovementTransport : 1;
|
||||
bool Stationary : 1;
|
||||
bool CombatVictim : 1;
|
||||
bool ServerTime : 1;
|
||||
bool Vehicle : 1;
|
||||
bool AnimKit : 1;
|
||||
bool Rotation : 1;
|
||||
bool GameObject : 1;
|
||||
bool SmoothPhasing : 1;
|
||||
bool ThisIsYou : 1;
|
||||
bool SceneObject : 1;
|
||||
bool ActivePlayer : 1;
|
||||
bool Conversation : 1;
|
||||
bool Room : 1;
|
||||
bool Decor : 1;
|
||||
bool MeshObject : 1;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
memset(this, 0, sizeof(CreateObjectBits));
|
||||
}
|
||||
};
|
||||
|
||||
namespace UF
|
||||
{
|
||||
class UpdateFieldHolder
|
||||
{
|
||||
public:
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline MutableFieldReference<T, false> ModifyValue(UpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline OptionalUpdateFieldSetter<T> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline MutableFieldReference<T, false> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field), uint32 /*dummy*/);
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void ClearChangesMask(UpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
uint32 GetChangedObjectTypeMask() const { return _changesMask; }
|
||||
|
||||
bool HasChanged(uint32 index) const { return (_changesMask & UpdateMaskHelpers::GetBlockFlag(index)) != 0; }
|
||||
|
||||
inline BaseEntity* GetOwner();
|
||||
|
||||
private:
|
||||
friend BaseEntity;
|
||||
|
||||
// This class is tightly tied to BaseEntity::m_values member, do not construct elsewhere
|
||||
UpdateFieldHolder() = default;
|
||||
|
||||
uint32 _changesMask = 0; // changes mask for data of Object subclasses
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool SetUpdateFieldValue(UpdateFieldPrivateSetter<T>& setter, typename UpdateFieldPrivateSetter<T>::value_type&& value)
|
||||
{
|
||||
return setter.SetValue(std::move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
return setter.AddValue();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
|
||||
{
|
||||
return setter.InsertValue(index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
|
||||
{
|
||||
setter.RemoveValue(index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
setter.Clear();
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
|
||||
{
|
||||
setter.RemoveKey(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
setter.RemoveValue();
|
||||
}
|
||||
}
|
||||
|
||||
class TC_GAME_API BaseEntity
|
||||
{
|
||||
ObjectGuid m_guid;
|
||||
|
||||
public:
|
||||
virtual ~BaseEntity();
|
||||
|
||||
bool IsInWorld() const { return m_inWorld; }
|
||||
|
||||
virtual void AddToWorld();
|
||||
virtual void RemoveFromWorld();
|
||||
|
||||
static ObjectGuid GetGUID(BaseEntity const* o) { return o ? o->GetGUID() : ObjectGuid::Empty; }
|
||||
ObjectGuid const& GetGUID() const { return m_guid; }
|
||||
|
||||
TypeID GetTypeId() const { return m_objectTypeId; }
|
||||
bool isType(TypeMask mask) const { return (ObjectTypeMask[m_objectTypeId] & mask) != 0; }
|
||||
|
||||
inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); }
|
||||
inline bool IsItem() const { return isType(TYPEMASK_ITEM); }
|
||||
inline bool IsUnit() const { return isType(TYPEMASK_UNIT); }
|
||||
inline bool IsCreature() const { return GetTypeId() == TYPEID_UNIT; }
|
||||
inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; }
|
||||
inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; }
|
||||
inline bool IsDynObject() const { return GetTypeId() == TYPEID_DYNAMICOBJECT; }
|
||||
inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; }
|
||||
inline bool IsAreaTrigger() const { return GetTypeId() == TYPEID_AREATRIGGER; }
|
||||
inline bool IsSceneObject() const { return GetTypeId() == TYPEID_SCENEOBJECT; }
|
||||
inline bool IsConversation() const { return GetTypeId() == TYPEID_CONVERSATION; }
|
||||
inline bool IsMeshObject() const { return GetTypeId() == TYPEID_MESH_OBJECT; }
|
||||
|
||||
virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
|
||||
void SendUpdateToPlayer(Player* player) const;
|
||||
|
||||
void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const;
|
||||
void BuildDestroyUpdateBlock(UpdateData* data) const;
|
||||
void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
|
||||
ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
|
||||
|
||||
virtual void DestroyForPlayer(Player const* target) const;
|
||||
void SendOutOfRangeForPlayer(Player const* target) const;
|
||||
|
||||
virtual void ClearUpdateMask(bool remove);
|
||||
|
||||
virtual std::string GetNameForLocaleIdx(LocaleConstant locale) const = 0;
|
||||
|
||||
void SetIsNewObject(bool enable) { m_isNewObject = enable; }
|
||||
bool IsDestroyedObject() const { return m_isDestroyedObject; }
|
||||
void SetDestroyedObject(bool destroyed) { m_isDestroyedObject = destroyed; }
|
||||
virtual void BuildUpdate([[maybe_unused]] UpdateDataMapType& data_map) { }
|
||||
void BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const;
|
||||
|
||||
friend UF::UpdateFieldHolder;
|
||||
UF::UpdateFieldHolder m_values;
|
||||
|
||||
template<typename T>
|
||||
void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter<T> const& /*setter*/)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
|
||||
virtual std::string GetDebugInfo() const;
|
||||
|
||||
protected:
|
||||
BaseEntity();
|
||||
|
||||
void _Create(ObjectGuid const& guid) { m_guid = guid; }
|
||||
|
||||
template<typename T>
|
||||
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
|
||||
{
|
||||
if (UF::SetUpdateFieldValue(setter, std::move(value)))
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "SetUpdateFieldFlagValue must be used with integral types");
|
||||
this->SetUpdateFieldValue(setter, setter.GetValue() | flag);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "RemoveUpdateFieldFlagValue must be used with integral types");
|
||||
this->SetUpdateFieldValue(setter, setter.GetValue() & ~flag);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename UF::DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
return UF::AddDynamicUpdateFieldValue(setter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename UF::DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
return UF::InsertDynamicUpdateFieldValue(setter, index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveDynamicUpdateFieldValue(setter, index);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveMapUpdateFieldValue(setter, key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::ClearDynamicUpdateFieldValues(setter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveOptionalUpdateFieldValue(setter);
|
||||
}
|
||||
|
||||
// stat system helpers
|
||||
template<typename T>
|
||||
void SetUpdateFieldStatValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
this->SetUpdateFieldValue(setter, std::max(value, T(0)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ApplyModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type mod, bool apply)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
|
||||
T value = setter.GetValue();
|
||||
if (apply)
|
||||
value += mod;
|
||||
else
|
||||
value -= mod;
|
||||
|
||||
this->SetUpdateFieldValue(setter, value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, float percent, bool apply)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
|
||||
T value = setter.GetValue();
|
||||
|
||||
// don't want to include Util.h here
|
||||
//ApplyPercentModFloatVar(value, percent, apply);
|
||||
if (percent == -100.0f)
|
||||
percent = -99.99f;
|
||||
value *= (apply ? (100.0f + percent) / 100.0f : 100.0f / (100.0f + percent));
|
||||
|
||||
this->SetUpdateFieldValue(setter, value);
|
||||
}
|
||||
|
||||
template<typename Action>
|
||||
void DoWithSuppressingObjectUpdates(Action&& action)
|
||||
{
|
||||
bool wasUpdatedBeforeAction = m_objectUpdated;
|
||||
action();
|
||||
if (m_objectUpdated && !wasUpdatedBeforeAction)
|
||||
{
|
||||
RemoveFromObjectUpdate();
|
||||
m_objectUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const;
|
||||
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const;
|
||||
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);
|
||||
CreateObjectBits m_updateFlag = {};
|
||||
WowCS::EntityFragmentsHolder m_entityFragments;
|
||||
|
||||
virtual bool AddToObjectUpdate() = 0;
|
||||
virtual void RemoveFromObjectUpdate() = 0;
|
||||
void AddToObjectUpdateIfNeeded();
|
||||
|
||||
bool m_objectUpdated = false;
|
||||
|
||||
private:
|
||||
bool m_inWorld = false;
|
||||
bool m_isNewObject = false;
|
||||
bool m_isDestroyedObject = false;
|
||||
|
||||
BaseEntity(BaseEntity const& right) = delete;
|
||||
BaseEntity(BaseEntity&& right) = delete;
|
||||
BaseEntity& operator=(BaseEntity const& right) = delete;
|
||||
BaseEntity& operator=(BaseEntity&& right) = delete;
|
||||
};
|
||||
|
||||
inline BaseEntity* UF::UpdateFieldHolder::GetOwner()
|
||||
{
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<BaseEntity*>(reinterpret_cast<std::byte*>(this) - offsetof(BaseEntity, m_values));
|
||||
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(UpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
BaseEntity* owner = GetOwner();
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
return { static_cast<Derived*>(owner)->*field };
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field, uint32 /*dummy*/)
|
||||
{
|
||||
BaseEntity* owner = GetOwner();
|
||||
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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
BaseEntity* owner = GetOwner();
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
{
|
||||
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
if (!_changesMask)
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
}
|
||||
else
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
|
||||
auto& uf = (static_cast<Derived*>(owner)->*field);
|
||||
if (uf.has_value())
|
||||
uf._value->ClearChangesMask();
|
||||
}
|
||||
|
||||
#endif // TRINITYCORE_BASE_ENTITY_H
|
||||
@@ -20,19 +20,16 @@
|
||||
#include "CellImpl.h"
|
||||
#include "CinematicMgr.h"
|
||||
#include "CombatLogPackets.h"
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "Corpse.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "GameTime.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "GameObject.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "G3DPosition.hpp"
|
||||
#include "InstanceScenario.h"
|
||||
#include "Item.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "MovementPackets.h"
|
||||
#include "MovementTypedefs.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
@@ -41,17 +38,14 @@
|
||||
#include "Player.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "SmoothPhasing.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellPackets.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Totem.h"
|
||||
#include "Transport.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateData.h"
|
||||
#include "Util.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "Vehicle.h"
|
||||
#include "VMapManager.h"
|
||||
#include "World.h"
|
||||
#include <G3D/Vector3.h>
|
||||
@@ -73,46 +67,13 @@ Object::Object() : m_scriptRef(this, NoopObjectDeleter())
|
||||
m_updateFlag.Clear();
|
||||
|
||||
m_entityFragments.Add(WowCS::EntityFragment::CGObject, false);
|
||||
|
||||
m_inWorld = false;
|
||||
m_isNewObject = false;
|
||||
m_isDestroyedObject = false;
|
||||
m_objectUpdated = false;
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
if (IsInWorld())
|
||||
{
|
||||
TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in world!!", GetGUID().ToString());
|
||||
if (Item* item = ToItem())
|
||||
TC_LOG_FATAL("misc", "Item slot {}", item->GetSlot());
|
||||
ABORT();
|
||||
}
|
||||
|
||||
if (m_objectUpdated)
|
||||
{
|
||||
TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in update list!!", GetGUID().ToString());
|
||||
ABORT();
|
||||
}
|
||||
}
|
||||
|
||||
void Object::_Create(ObjectGuid const& guid)
|
||||
{
|
||||
m_objectUpdated = false;
|
||||
m_guid = guid;
|
||||
}
|
||||
Object::~Object() = default;
|
||||
|
||||
void Object::AddToWorld()
|
||||
{
|
||||
if (m_inWorld)
|
||||
return;
|
||||
|
||||
m_inWorld = true;
|
||||
|
||||
// synchronize values mirror with values array (changes will send in updatecreate opcode any way
|
||||
ASSERT(!m_objectUpdated);
|
||||
ClearUpdateMask(false);
|
||||
BaseEntity::AddToWorld();
|
||||
|
||||
// Set new ref when adding to world (except if we already have one - also set in constructor to allow scripts to work in initialization phase)
|
||||
// Changing the ref when adding/removing from world prevents accessing players on different maps (possibly from another thread)
|
||||
@@ -122,95 +83,11 @@ void Object::AddToWorld()
|
||||
|
||||
void Object::RemoveFromWorld()
|
||||
{
|
||||
if (!m_inWorld)
|
||||
return;
|
||||
|
||||
m_inWorld = false;
|
||||
|
||||
// if we remove from world then sending changes not required
|
||||
ClearUpdateMask(true);
|
||||
BaseEntity::RemoveFromWorld();
|
||||
|
||||
m_scriptRef = nullptr;
|
||||
}
|
||||
|
||||
void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
uint8 updateType = m_isNewObject ? UPDATETYPE_CREATE_OBJECT2 : UPDATETYPE_CREATE_OBJECT;
|
||||
uint8 objectType = m_objectTypeId;
|
||||
CreateObjectBits flags = m_updateFlag;
|
||||
|
||||
if (target == this) // building packet for yourself
|
||||
{
|
||||
flags.ThisIsYou = true;
|
||||
flags.ActivePlayer = true;
|
||||
objectType = TYPEID_ACTIVE_PLAYER;
|
||||
}
|
||||
|
||||
if (IsWorldObject())
|
||||
{
|
||||
WorldObject const* worldObject = static_cast<WorldObject const*>(this);
|
||||
if (worldObject->GetSmoothPhasing() && worldObject->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID()))
|
||||
flags.SmoothPhasing = true;
|
||||
}
|
||||
|
||||
ByteBuffer& buf = data->GetBuffer();
|
||||
buf << uint8(updateType);
|
||||
buf << GetGUID();
|
||||
buf << uint8(objectType);
|
||||
|
||||
BuildMovementUpdate(&buf, flags, target);
|
||||
|
||||
UF::UpdateFieldFlag fieldFlags = GetUpdateFieldFlagsFor(target);
|
||||
std::size_t sizePos = buf.wpos();
|
||||
buf << uint32(0);
|
||||
buf << uint8(fieldFlags);
|
||||
BuildEntityFragments(&buf, m_entityFragments.GetIds());
|
||||
buf << uint8(1); // IndirectFragmentActive: CGObject
|
||||
BuildValuesCreate(&buf, fieldFlags, target);
|
||||
buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
|
||||
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void Object::SendUpdateToPlayer(Player* player)
|
||||
{
|
||||
// send create update to player
|
||||
UpdateData upd(player->GetMapId());
|
||||
WorldPacket packet;
|
||||
|
||||
if (player->HaveAtClient(this))
|
||||
BuildValuesUpdateBlockForPlayer(&upd, player);
|
||||
else
|
||||
BuildCreateUpdateBlockForPlayer(&upd, player);
|
||||
upd.BuildPacket(&packet);
|
||||
player->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const
|
||||
{
|
||||
ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
|
||||
|
||||
EnumFlag<UF::UpdateFieldFlag> fieldFlags = GetUpdateFieldFlagsFor(target);
|
||||
std::size_t sizePos = buf.wpos();
|
||||
buf << uint32(0);
|
||||
buf << uint8(fieldFlags.HasFlag(UF::UpdateFieldFlag::Owner));
|
||||
buf << uint8(m_entityFragments.IdsChanged);
|
||||
if (m_entityFragments.IdsChanged)
|
||||
{
|
||||
buf << uint8(WowCS::EntityFragmentSerializationType::Full);
|
||||
BuildEntityFragments(&buf, m_entityFragments.GetIds());
|
||||
}
|
||||
buf << uint8(m_entityFragments.ContentsChangedMask);
|
||||
|
||||
BuildValuesUpdate(&buf, fieldFlags, target);
|
||||
buf.put<uint32>(sizePos, buf.wpos() - sizePos - 4);
|
||||
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::UpdateFieldFlag flags, Player const* target) const
|
||||
{
|
||||
ByteBuffer& buf = PrepareValuesUpdateBuffer(data);
|
||||
@@ -224,12 +101,6 @@ void Object::BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::Updat
|
||||
data->AddUpdateBlock();
|
||||
}
|
||||
|
||||
void Object::BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments)
|
||||
{
|
||||
data->append(fragments.data(), fragments.size());
|
||||
*data << uint8(WowCS::EntityFragment::End);
|
||||
}
|
||||
|
||||
void Object::BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags) const
|
||||
{
|
||||
uint8 contentsChangedMask = WowCS::CGObjectChangedMask;
|
||||
@@ -242,505 +113,22 @@ void Object::BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* da
|
||||
*data << uint8(contentsChangedMask);
|
||||
}
|
||||
|
||||
void Object::BuildDestroyUpdateBlock(UpdateData* data) const
|
||||
{
|
||||
data->AddDestroyObject(GetGUID());
|
||||
}
|
||||
|
||||
void Object::BuildOutOfRangeUpdateBlock(UpdateData* data) const
|
||||
{
|
||||
data->AddOutOfRangeGUID(GetGUID());
|
||||
}
|
||||
|
||||
ByteBuffer& Object::PrepareValuesUpdateBuffer(UpdateData* data) const
|
||||
{
|
||||
ByteBuffer& buffer = data->GetBuffer();
|
||||
buffer << uint8(UPDATETYPE_VALUES);
|
||||
buffer << GetGUID();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Object::DestroyForPlayer(Player const* target) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
UpdateData updateData(target->GetMapId());
|
||||
BuildDestroyUpdateBlock(&updateData);
|
||||
WorldPacket packet;
|
||||
updateData.BuildPacket(&packet);
|
||||
target->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Object::SendOutOfRangeForPlayer(Player const* target) const
|
||||
{
|
||||
ASSERT(target);
|
||||
|
||||
UpdateData updateData(target->GetMapId());
|
||||
BuildOutOfRangeUpdateBlock(&updateData);
|
||||
WorldPacket packet;
|
||||
updateData.BuildPacket(&packet);
|
||||
target->SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const
|
||||
{
|
||||
std::span<uint32 const> PauseTimes;
|
||||
if (IsGameObject())
|
||||
PauseTimes = static_cast<GameObject const*>(this)->GetPauseTimes();
|
||||
|
||||
data->WriteBit(IsWorldObject()); // HasPositionFragment
|
||||
data->WriteBit(flags.NoBirthAnim);
|
||||
data->WriteBit(flags.EnablePortals);
|
||||
data->WriteBit(flags.PlayHoverAnim);
|
||||
data->WriteBit(flags.ThisIsYou);
|
||||
data->WriteBit(flags.MovementUpdate);
|
||||
data->WriteBit(flags.MovementTransport);
|
||||
data->WriteBit(flags.Stationary);
|
||||
data->WriteBit(flags.CombatVictim);
|
||||
data->WriteBit(flags.ServerTime);
|
||||
data->WriteBit(flags.Vehicle);
|
||||
data->WriteBit(flags.AnimKit);
|
||||
data->WriteBit(flags.Rotation);
|
||||
data->WriteBit(flags.GameObject);
|
||||
data->WriteBit(flags.SmoothPhasing);
|
||||
data->WriteBit(flags.SceneObject);
|
||||
data->WriteBit(flags.ActivePlayer);
|
||||
data->WriteBit(flags.Conversation);
|
||||
data->WriteBit(flags.Room);
|
||||
data->WriteBit(flags.Decor);
|
||||
data->WriteBit(flags.MeshObject);
|
||||
data->FlushBits();
|
||||
|
||||
if (flags.MovementUpdate)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
bool HasFallDirection = unit->HasUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||
bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0;
|
||||
bool HasSpline = unit->IsSplineEnabled();
|
||||
bool HasInertia = unit->m_movementInfo.inertia.has_value();
|
||||
bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value();
|
||||
bool HasDriveStatus = unit->m_movementInfo.driveStatus.has_value();
|
||||
bool HasStandingOnGameObjectGUID = unit->m_movementInfo.standingOnGameObjectGUID.has_value();
|
||||
|
||||
*data << GetGUID(); // MoverGUID
|
||||
|
||||
*data << uint32(unit->GetUnitMovementFlags());
|
||||
*data << uint32(unit->GetExtraUnitMovementFlags());
|
||||
*data << uint32(unit->GetExtraUnitMovementFlags2());
|
||||
|
||||
*data << uint32(unit->m_movementInfo.time); // MoveTime
|
||||
*data << float(unit->GetPositionX());
|
||||
*data << float(unit->GetPositionY());
|
||||
*data << float(unit->GetPositionZ());
|
||||
*data << float(unit->GetOrientation());
|
||||
|
||||
*data << float(unit->m_movementInfo.pitch); // Pitch
|
||||
*data << float(unit->m_movementInfo.stepUpStartElevation); // StepUpStartElevation
|
||||
|
||||
*data << uint32(0); // RemoveForcesIDs.size()
|
||||
*data << uint32(0); // MoveIndex
|
||||
|
||||
//for (std::size_t i = 0; i < RemoveForcesIDs.size(); ++i)
|
||||
// *data << ObjectGuid(RemoveForcesIDs);
|
||||
|
||||
data->WriteBit(HasStandingOnGameObjectGUID); // HasStandingOnGameObjectGUID
|
||||
data->WriteBit(!unit->m_movementInfo.transport.guid.IsEmpty()); // HasTransport
|
||||
data->WriteBit(HasFall); // HasFall
|
||||
data->WriteBit(HasSpline); // HasSpline - marks that the unit uses spline movement
|
||||
data->WriteBit(false); // HeightChangeFailed
|
||||
data->WriteBit(false); // RemoteTimeValid
|
||||
data->WriteBit(HasInertia); // HasInertia
|
||||
data->WriteBit(HasAdvFlying); // HasAdvFlying
|
||||
data->WriteBit(HasDriveStatus); // HasDriveStatus
|
||||
data->FlushBits();
|
||||
|
||||
if (!unit->m_movementInfo.transport.guid.IsEmpty())
|
||||
*data << unit->m_movementInfo.transport;
|
||||
|
||||
if (HasStandingOnGameObjectGUID)
|
||||
*data << *unit->m_movementInfo.standingOnGameObjectGUID;
|
||||
|
||||
if (HasInertia)
|
||||
{
|
||||
*data << unit->m_movementInfo.inertia->id;
|
||||
*data << unit->m_movementInfo.inertia->force.PositionXYZStream();
|
||||
*data << uint32(unit->m_movementInfo.inertia->lifetime);
|
||||
}
|
||||
|
||||
if (HasAdvFlying)
|
||||
{
|
||||
*data << float(unit->m_movementInfo.advFlying->forwardVelocity);
|
||||
*data << float(unit->m_movementInfo.advFlying->upVelocity);
|
||||
}
|
||||
|
||||
if (HasFall)
|
||||
{
|
||||
*data << uint32(unit->m_movementInfo.jump.fallTime); // Time
|
||||
*data << float(unit->m_movementInfo.jump.zspeed); // JumpVelocity
|
||||
|
||||
if (data->WriteBit(HasFallDirection))
|
||||
{
|
||||
*data << float(unit->m_movementInfo.jump.sinAngle); // Direction
|
||||
*data << float(unit->m_movementInfo.jump.cosAngle);
|
||||
*data << float(unit->m_movementInfo.jump.xyspeed); // Speed
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDriveStatus)
|
||||
{
|
||||
*data << float(unit->m_movementInfo.driveStatus->speed);
|
||||
*data << float(unit->m_movementInfo.driveStatus->movementAngle);
|
||||
data->WriteBit(unit->m_movementInfo.driveStatus->accelerating);
|
||||
data->WriteBit(unit->m_movementInfo.driveStatus->drifting);
|
||||
data->FlushBits();
|
||||
}
|
||||
|
||||
*data << float(unit->GetSpeed(MOVE_WALK));
|
||||
*data << float(unit->GetSpeed(MOVE_RUN));
|
||||
*data << float(unit->GetSpeed(MOVE_RUN_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_SWIM));
|
||||
*data << float(unit->GetSpeed(MOVE_SWIM_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_FLIGHT));
|
||||
*data << float(unit->GetSpeed(MOVE_FLIGHT_BACK));
|
||||
*data << float(unit->GetSpeed(MOVE_TURN_RATE));
|
||||
*data << float(unit->GetSpeed(MOVE_PITCH_RATE));
|
||||
|
||||
if (MovementForces const* movementForces = unit->GetMovementForces())
|
||||
{
|
||||
*data << uint32(movementForces->GetForces()->size());
|
||||
*data << float(movementForces->GetModMagnitude()); // MovementForcesModMagnitude
|
||||
}
|
||||
else
|
||||
{
|
||||
*data << uint32(0);
|
||||
*data << float(1.0f); // MovementForcesModMagnitude
|
||||
}
|
||||
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_AIR_FRICTION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_MAX_VEL));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LIFT_COEFFICIENT));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_DOUBLE_JUMP_VEL_MOD));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_GLIDE_START_MIN_HEIGHT));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_ADD_IMPULSE_MAX_SPEED));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_BANKING_RATE));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_BANKING_RATE));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_DOWN));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_DOWN));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_PITCHING_RATE_UP));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_PITCHING_RATE_UP));
|
||||
*data << float(unit->GetAdvFlyingSpeedMin(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
|
||||
*data << float(unit->GetAdvFlyingSpeedMax(ADV_FLYING_TURN_VELOCITY_THRESHOLD));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_SURFACE_FRICTION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_OVER_MAX_DECELERATION));
|
||||
*data << float(unit->GetAdvFlyingSpeed(ADV_FLYING_LAUNCH_SPEED_COEFFICIENT));
|
||||
|
||||
data->WriteBit(HasSpline);
|
||||
data->FlushBits();
|
||||
|
||||
if (MovementForces const* movementForces = unit->GetMovementForces())
|
||||
for (MovementForce const& force : *movementForces->GetForces())
|
||||
WorldPackets::Movement::CommonMovement::WriteMovementForceWithDirection(force, *data, unit);
|
||||
|
||||
if (HasSpline)
|
||||
WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(*unit->movespline, *data);
|
||||
}
|
||||
|
||||
*data << uint32(PauseTimes.size());
|
||||
|
||||
if (flags.Stationary)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << self->GetStationaryPosition().PositionXYZOStream();
|
||||
}
|
||||
|
||||
if (flags.CombatVictim)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
*data << unit->GetVictim()->GetGUID(); // CombatVictim
|
||||
}
|
||||
|
||||
if (flags.ServerTime)
|
||||
*data << uint32(GameTime::GetGameTimeMS());
|
||||
|
||||
if (flags.Vehicle)
|
||||
{
|
||||
Unit const* unit = static_cast<Unit const*>(this);
|
||||
*data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID
|
||||
*data << float(unit->GetOrientation()); // InitialRawFacing
|
||||
}
|
||||
|
||||
if (flags.AnimKit)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << uint16(self->GetAIAnimKitId()); // AiID
|
||||
*data << uint16(self->GetMovementAnimKitId()); // MovementID
|
||||
*data << uint16(self->GetMeleeAnimKitId()); // MeleeID
|
||||
}
|
||||
|
||||
if (flags.Rotation)
|
||||
{
|
||||
GameObject const* gameObject = static_cast<GameObject const*>(this);
|
||||
*data << uint64(gameObject->GetPackedLocalRotation()); // Rotation
|
||||
}
|
||||
|
||||
//if (flags.Room)
|
||||
// *data << ObjectGuid(HouseGUID);
|
||||
|
||||
//if (flags.Decor)
|
||||
// *data << ObjectGuid(RoomGUID);
|
||||
|
||||
//if (flags.MeshObject)
|
||||
//{
|
||||
// *data << ObjectGuid(AttachParentGUID);
|
||||
// *data << TaggedPosition<Position::XYZ>(PositionLocalSpace);
|
||||
// *data << QuaternionData(RotationLocalSpace);
|
||||
// *data << float(ScaleLocalSpace);
|
||||
// *data << uint8(AttachmentFlags);
|
||||
//}
|
||||
|
||||
if (!PauseTimes.empty())
|
||||
data->append(PauseTimes.data(), PauseTimes.size());
|
||||
|
||||
if (flags.MovementTransport)
|
||||
{
|
||||
WorldObject const* self = static_cast<WorldObject const*>(this);
|
||||
*data << self->m_movementInfo.transport;
|
||||
}
|
||||
|
||||
if (flags.GameObject)
|
||||
{
|
||||
GameObject const* gameObject = static_cast<GameObject const*>(this);
|
||||
Transport const* transport = gameObject->ToTransport();
|
||||
|
||||
bool bit8 = false;
|
||||
|
||||
*data << uint32(gameObject->GetWorldEffectID());
|
||||
|
||||
data->WriteBit(bit8);
|
||||
data->WriteBit(transport != nullptr);
|
||||
data->WriteBit(gameObject->GetPathProgressForClient().has_value());
|
||||
data->FlushBits();
|
||||
if (transport)
|
||||
{
|
||||
uint32 period = transport->GetTransportPeriod();
|
||||
|
||||
*data << uint32((((int64(transport->GetTimer()) - int64(GameTime::GetGameTimeMS())) % period) + period) % period); // TimeOffset
|
||||
*data << uint32(transport->GetNextStopTimestamp().value_or(0));
|
||||
data->WriteBit(transport->GetNextStopTimestamp().has_value());
|
||||
data->WriteBit(transport->IsStopped());
|
||||
data->WriteBit(false);
|
||||
data->FlushBits();
|
||||
}
|
||||
|
||||
if (bit8)
|
||||
*data << uint32(0);
|
||||
|
||||
if (gameObject->GetPathProgressForClient())
|
||||
*data << float(*gameObject->GetPathProgressForClient());
|
||||
}
|
||||
|
||||
if (flags.SmoothPhasing)
|
||||
{
|
||||
SmoothPhasingInfo const* smoothPhasingInfo = static_cast<WorldObject const*>(this)->GetSmoothPhasing()->GetInfoForSeer(target->GetGUID());
|
||||
ASSERT(smoothPhasingInfo);
|
||||
|
||||
data->WriteBit(smoothPhasingInfo->ReplaceActive);
|
||||
data->WriteBit(smoothPhasingInfo->StopAnimKits);
|
||||
data->WriteBit(smoothPhasingInfo->ReplaceObject.has_value());
|
||||
data->FlushBits();
|
||||
if (smoothPhasingInfo->ReplaceObject)
|
||||
*data << *smoothPhasingInfo->ReplaceObject;
|
||||
}
|
||||
|
||||
if (flags.SceneObject)
|
||||
{
|
||||
data->WriteBit(false); // HasLocalScriptData
|
||||
data->WriteBit(false); // HasPetBattleFullUpdate
|
||||
data->FlushBits();
|
||||
|
||||
// if (HasLocalScriptData)
|
||||
// {
|
||||
// data->WriteBits(Data.length(), 7);
|
||||
// data->FlushBits();
|
||||
// data->WriteString(Data);
|
||||
// }
|
||||
|
||||
// if (HasPetBattleFullUpdate)
|
||||
// {
|
||||
// for (std::size_t i = 0; i < 2; ++i)
|
||||
// {
|
||||
// *data << ObjectGuid(Players[i].CharacterID);
|
||||
// *data << int32(Players[i].TrapAbilityID);
|
||||
// *data << int32(Players[i].TrapStatus);
|
||||
// *data << uint16(Players[i].RoundTimeSecs);
|
||||
// *data << int8(Players[i].FrontPet);
|
||||
// *data << uint8(Players[i].InputFlags);
|
||||
|
||||
// data->WriteBits(Players[i].Pets.size(), 2);
|
||||
// data->FlushBits();
|
||||
// for (std::size_t j = 0; j < Players[i].Pets.size(); ++j)
|
||||
// {
|
||||
// *data << ObjectGuid(Players[i].Pets[j].BattlePetGUID);
|
||||
// *data << int32(Players[i].Pets[j].SpeciesID);
|
||||
// *data << int32(Players[i].Pets[j].CreatureID);
|
||||
// *data << int32(Players[i].Pets[j].DisplayID);
|
||||
// *data << int16(Players[i].Pets[j].Level);
|
||||
// *data << int16(Players[i].Pets[j].Xp);
|
||||
// *data << int32(Players[i].Pets[j].CurHealth);
|
||||
// *data << int32(Players[i].Pets[j].MaxHealth);
|
||||
// *data << int32(Players[i].Pets[j].Power);
|
||||
// *data << int32(Players[i].Pets[j].Speed);
|
||||
// *data << int32(Players[i].Pets[j].NpcTeamMemberID);
|
||||
// *data << uint8(Players[i].Pets[j].BreedQuality);
|
||||
// *data << uint16(Players[i].Pets[j].StatusFlags);
|
||||
// *data << int8(Players[i].Pets[j].Slot);
|
||||
|
||||
// *data << uint32(Players[i].Pets[j].Abilities.size());
|
||||
// *data << uint32(Players[i].Pets[j].Auras.size());
|
||||
// *data << uint32(Players[i].Pets[j].States.size());
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].Abilities.size(); ++k)
|
||||
// {
|
||||
// *data << int32(Players[i].Pets[j].Abilities[k].AbilityID);
|
||||
// *data << int16(Players[i].Pets[j].Abilities[k].CooldownRemaining);
|
||||
// *data << int16(Players[i].Pets[j].Abilities[k].LockdownRemaining);
|
||||
// *data << int8(Players[i].Pets[j].Abilities[k].AbilityIndex);
|
||||
// *data << uint8(Players[i].Pets[j].Abilities[k].Pboid);
|
||||
// }
|
||||
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].Auras.size(); ++k)
|
||||
// {
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].AbilityID);
|
||||
// *data << uint32(Players[i].Pets[j].Auras[k].InstanceID);
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].RoundsRemaining);
|
||||
// *data << int32(Players[i].Pets[j].Auras[k].CurrentRound);
|
||||
// *data << uint8(Players[i].Pets[j].Auras[k].CasterPBOID);
|
||||
// }
|
||||
|
||||
// for (std::size_t k = 0; k < Players[i].Pets[j].States.size(); ++k)
|
||||
// {
|
||||
// *data << uint32(Players[i].Pets[j].States[k].StateID);
|
||||
// *data << int32(Players[i].Pets[j].States[k].StateValue);
|
||||
// }
|
||||
|
||||
// data->WriteBits(Players[i].Pets[j].CustomName.length(), 7);
|
||||
// data->FlushBits();
|
||||
// data->WriteString(Players[i].Pets[j].CustomName);
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (std::size_t i = 0; i < 3; ++i)
|
||||
// {
|
||||
// *data << uint32(Enviros[j].Auras.size());
|
||||
// *data << uint32(Enviros[j].States.size());
|
||||
// for (std::size_t j = 0; j < Enviros[j].Auras.size(); ++j)
|
||||
// {
|
||||
// *data << int32(Enviros[j].Auras[j].AbilityID);
|
||||
// *data << uint32(Enviros[j].Auras[j].InstanceID);
|
||||
// *data << int32(Enviros[j].Auras[j].RoundsRemaining);
|
||||
// *data << int32(Enviros[j].Auras[j].CurrentRound);
|
||||
// *data << uint8(Enviros[j].Auras[j].CasterPBOID);
|
||||
// }
|
||||
|
||||
// for (std::size_t j = 0; j < Enviros[j].States.size(); ++j)
|
||||
// {
|
||||
// *data << uint32(Enviros[i].States[j].StateID);
|
||||
// *data << int32(Enviros[i].States[j].StateValue);
|
||||
// }
|
||||
// }
|
||||
|
||||
// *data << uint16(WaitingForFrontPetsMaxSecs);
|
||||
// *data << uint16(PvpMaxRoundTime);
|
||||
// *data << int32(CurRound);
|
||||
// *data << uint32(NpcCreatureID);
|
||||
// *data << uint32(NpcDisplayID);
|
||||
// *data << int8(CurPetBattleState);
|
||||
// *data << uint8(ForfeitPenalty);
|
||||
// *data << ObjectGuid(InitialWildPetGUID);
|
||||
// data->WriteBit(IsPVP);
|
||||
// data->WriteBit(CanAwardXP);
|
||||
// data->FlushBits();
|
||||
// }
|
||||
}
|
||||
|
||||
if (flags.ActivePlayer)
|
||||
{
|
||||
Player const* player = static_cast<Player const*>(this);
|
||||
|
||||
bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty();
|
||||
bool HasRuneState = player->GetPowerIndex(POWER_RUNES) != MAX_POWERS;
|
||||
|
||||
data->WriteBit(HasSceneInstanceIDs);
|
||||
data->WriteBit(HasRuneState);
|
||||
data->FlushBits();
|
||||
if (HasSceneInstanceIDs)
|
||||
{
|
||||
*data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size());
|
||||
for (auto const& [sceneInstanceId, _] : player->GetSceneMgr().GetSceneTemplateByInstanceMap())
|
||||
*data << uint32(sceneInstanceId);
|
||||
}
|
||||
if (HasRuneState)
|
||||
{
|
||||
float baseCd = float(player->GetRuneBaseCooldown());
|
||||
uint32 maxRunes = uint32(player->GetMaxPower(POWER_RUNES));
|
||||
|
||||
*data << uint8((1 << maxRunes) - 1);
|
||||
*data << uint8(player->GetRunesState());
|
||||
*data << uint32(maxRunes);
|
||||
for (uint32 i = 0; i < maxRunes; ++i)
|
||||
*data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.Conversation)
|
||||
{
|
||||
Conversation const* self = static_cast<Conversation const*>(this);
|
||||
if (data->WriteBit(self->GetTextureKitId() != 0))
|
||||
*data << uint32(self->GetTextureKitId());
|
||||
|
||||
data->FlushBits();
|
||||
}
|
||||
}
|
||||
|
||||
UF::UpdateFieldFlag Object::GetUpdateFieldFlagsFor(Player const* /*target*/) const
|
||||
{
|
||||
return UF::UpdateFieldFlag::None;
|
||||
}
|
||||
|
||||
void Object::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag /*flags*/, Player const* /*target*/) const
|
||||
{
|
||||
*data << uint32(0);
|
||||
}
|
||||
|
||||
void Object::AddToObjectUpdateIfNeeded()
|
||||
{
|
||||
if (m_inWorld && !m_objectUpdated)
|
||||
m_objectUpdated = AddToObjectUpdate();
|
||||
}
|
||||
|
||||
void Object::ClearUpdateMask(bool remove)
|
||||
{
|
||||
m_values.ClearChangesMask(&Object::m_objectData);
|
||||
m_entityFragments.IdsChanged = false;
|
||||
|
||||
if (m_objectUpdated)
|
||||
{
|
||||
if (remove)
|
||||
RemoveFromObjectUpdate();
|
||||
m_objectUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
|
||||
{
|
||||
UpdateDataMapType::iterator iter = data_map.try_emplace(player, player->GetMapId()).first;
|
||||
BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
|
||||
BaseEntity::ClearUpdateMask(remove);
|
||||
}
|
||||
|
||||
std::string Object::GetDebugInfo() const
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << GetGUID().ToString() + " Entry " << GetEntry();
|
||||
return sstr.str();
|
||||
sstr << BaseEntity::GetDebugInfo() << " Entry " << GetEntry();
|
||||
return std::move(sstr).str();
|
||||
}
|
||||
|
||||
void MovementInfo::OutDebug()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef _OBJECT_H
|
||||
#define _OBJECT_H
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "Common.h"
|
||||
#include "Duration.h"
|
||||
#include "Errors.h"
|
||||
@@ -26,17 +27,13 @@
|
||||
#include "ModelIgnoreFlags.h"
|
||||
#include "MovementInfo.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Optional.h"
|
||||
#include "PhaseShift.h"
|
||||
#include "Position.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "UniqueTrackablePtr.h"
|
||||
#include "UpdateFields.h"
|
||||
#include "WowCSEntityDefinitions.h"
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
class AreaTrigger;
|
||||
class Conversation;
|
||||
@@ -78,132 +75,17 @@ namespace WorldPackets
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
|
||||
|
||||
struct CreateObjectBits
|
||||
{
|
||||
bool NoBirthAnim : 1;
|
||||
bool EnablePortals : 1;
|
||||
bool PlayHoverAnim : 1;
|
||||
bool MovementUpdate : 1;
|
||||
bool MovementTransport : 1;
|
||||
bool Stationary : 1;
|
||||
bool CombatVictim : 1;
|
||||
bool ServerTime : 1;
|
||||
bool Vehicle : 1;
|
||||
bool AnimKit : 1;
|
||||
bool Rotation : 1;
|
||||
bool GameObject : 1;
|
||||
bool SmoothPhasing : 1;
|
||||
bool ThisIsYou : 1;
|
||||
bool SceneObject : 1;
|
||||
bool ActivePlayer : 1;
|
||||
bool Conversation : 1;
|
||||
bool Room : 1;
|
||||
bool Decor : 1;
|
||||
bool MeshObject : 1;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
memset(this, 0, sizeof(CreateObjectBits));
|
||||
}
|
||||
};
|
||||
|
||||
namespace UF
|
||||
{
|
||||
class UpdateFieldHolder
|
||||
{
|
||||
public:
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline MutableFieldReference<T, false> ModifyValue(UpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline OptionalUpdateFieldSetter<T> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline MutableFieldReference<T, false> ModifyValue(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field), uint32 /*dummy*/);
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void ClearChangesMask(UpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
template<typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit>(Derived::* field));
|
||||
|
||||
uint32 GetChangedObjectTypeMask() const { return _changesMask; }
|
||||
|
||||
bool HasChanged(uint32 index) const { return (_changesMask & UpdateMaskHelpers::GetBlockFlag(index)) != 0; }
|
||||
|
||||
inline Object* GetOwner();
|
||||
|
||||
private:
|
||||
friend Object;
|
||||
|
||||
// This class is tightly tied to Object::m_values member, do not construct elsewhere
|
||||
UpdateFieldHolder() : _changesMask(0) { }
|
||||
|
||||
uint32 _changesMask;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool SetUpdateFieldValue(UpdateFieldPrivateSetter<T>& setter, typename UpdateFieldPrivateSetter<T>::value_type&& value)
|
||||
{
|
||||
return setter.SetValue(std::move(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
return setter.AddValue();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
|
||||
{
|
||||
return setter.InsertValue(index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter<T>& setter, uint32 index)
|
||||
{
|
||||
setter.RemoveValue(index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
setter.Clear();
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
inline void RemoveMapUpdateFieldValue(MapUpdateFieldSetter<K, V>& setter, std::type_identity_t<K> const& key)
|
||||
{
|
||||
setter.RemoveKey(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter<T>& setter)
|
||||
{
|
||||
setter.RemoveValue();
|
||||
}
|
||||
}
|
||||
|
||||
float const DEFAULT_COLLISION_HEIGHT = 2.03128f; // Most common value in dbc
|
||||
static constexpr Milliseconds const HEARTBEAT_INTERVAL = 5s + 200ms;
|
||||
|
||||
class TC_GAME_API Object
|
||||
class TC_GAME_API Object : public BaseEntity
|
||||
{
|
||||
ObjectGuid m_guid;
|
||||
|
||||
public:
|
||||
virtual ~Object();
|
||||
|
||||
bool IsInWorld() const { return m_inWorld; }
|
||||
void AddToWorld() override;
|
||||
void RemoveFromWorld() override;
|
||||
|
||||
virtual void AddToWorld();
|
||||
virtual void RemoveFromWorld();
|
||||
|
||||
static ObjectGuid GetGUID(Object const* o) { return o ? o->GetGUID() : ObjectGuid::Empty; }
|
||||
ObjectGuid const& GetGUID() const { return m_guid; }
|
||||
uint32 GetEntry() const { return m_objectData->EntryID; }
|
||||
void SetEntry(uint32 entry) { SetUpdateFieldValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::EntryID), entry); }
|
||||
|
||||
@@ -216,110 +98,71 @@ class TC_GAME_API Object
|
||||
void RemoveDynamicFlag(uint32 flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::DynamicFlags), flag); }
|
||||
void ReplaceAllDynamicFlags(uint32 flag) { SetUpdateFieldValue(m_values.ModifyValue(&Object::m_objectData).ModifyValue(&UF::ObjectData::DynamicFlags), flag); }
|
||||
|
||||
TypeID GetTypeId() const { return m_objectTypeId; }
|
||||
bool isType(TypeMask mask) const { return (ObjectTypeMask[m_objectTypeId] & mask) != 0; }
|
||||
|
||||
virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
|
||||
void SendUpdateToPlayer(Player* player);
|
||||
|
||||
void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player const* target) const;
|
||||
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData* data, UF::UpdateFieldFlag flags, Player const* target) const;
|
||||
void BuildDestroyUpdateBlock(UpdateData* data) const;
|
||||
void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
|
||||
ByteBuffer& PrepareValuesUpdateBuffer(UpdateData* data) const;
|
||||
|
||||
virtual void DestroyForPlayer(Player const* target) const;
|
||||
void SendOutOfRangeForPlayer(Player const* target) const;
|
||||
|
||||
virtual void ClearUpdateMask(bool remove);
|
||||
|
||||
virtual std::string GetNameForLocaleIdx(LocaleConstant locale) const = 0;
|
||||
void ClearUpdateMask(bool remove) override;
|
||||
|
||||
virtual bool hasQuest(uint32 /* quest_id */) const { return false; }
|
||||
virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; }
|
||||
void SetIsNewObject(bool enable) { m_isNewObject = enable; }
|
||||
bool IsDestroyedObject() const { return m_isDestroyedObject; }
|
||||
void SetDestroyedObject(bool destroyed) { m_isDestroyedObject = destroyed; }
|
||||
virtual void BuildUpdate(UpdateDataMapType&) { }
|
||||
void BuildFieldsUpdate(Player*, UpdateDataMapType &) const;
|
||||
|
||||
inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); }
|
||||
static WorldObject* ToWorldObject(Object* o) { return o ? o->ToWorldObject() : nullptr; }
|
||||
static WorldObject const* ToWorldObject(Object const* o) { return o ? o->ToWorldObject() : nullptr; }
|
||||
WorldObject* ToWorldObject() { if (IsWorldObject()) return reinterpret_cast<WorldObject*>(this); else return nullptr; }
|
||||
WorldObject const* ToWorldObject() const { if (IsWorldObject()) return reinterpret_cast<WorldObject const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsItem() const { return isType(TYPEMASK_ITEM); }
|
||||
static Item* ToItem(Object* o) { return o ? o->ToItem() : nullptr; }
|
||||
static Item const* ToItem(Object const* o) { return o ? o->ToItem() : nullptr; }
|
||||
Item* ToItem() { if (IsItem()) return reinterpret_cast<Item*>(this); else return nullptr; }
|
||||
Item const* ToItem() const { if (IsItem()) return reinterpret_cast<Item const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; }
|
||||
static Player* ToPlayer(Object* o) { return o ? o->ToPlayer() : nullptr; }
|
||||
static Player const* ToPlayer(Object const* o) { return o ? o->ToPlayer() : nullptr; }
|
||||
Player* ToPlayer() { if (IsPlayer()) return reinterpret_cast<Player*>(this); else return nullptr; }
|
||||
Player const* ToPlayer() const { if (IsPlayer()) return reinterpret_cast<Player const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsCreature() const { return GetTypeId() == TYPEID_UNIT; }
|
||||
static Creature* ToCreature(Object* o) { return o ? o->ToCreature() : nullptr; }
|
||||
static Creature const* ToCreature(Object const* o) { return o ? o->ToCreature() : nullptr; }
|
||||
Creature* ToCreature() { if (IsCreature()) return reinterpret_cast<Creature*>(this); else return nullptr; }
|
||||
Creature const* ToCreature() const { if (IsCreature()) return reinterpret_cast<Creature const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsUnit() const { return isType(TYPEMASK_UNIT); }
|
||||
static Unit* ToUnit(Object* o) { return o ? o->ToUnit() : nullptr; }
|
||||
static Unit const* ToUnit(Object const* o) { return o ? o->ToUnit() : nullptr; }
|
||||
Unit* ToUnit() { if (IsUnit()) return reinterpret_cast<Unit*>(this); else return nullptr; }
|
||||
Unit const* ToUnit() const { if (IsUnit()) return reinterpret_cast<Unit const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; }
|
||||
static GameObject* ToGameObject(Object* o) { return o ? o->ToGameObject() : nullptr; }
|
||||
static GameObject const* ToGameObject(Object const* o) { return o ? o->ToGameObject() : nullptr; }
|
||||
GameObject* ToGameObject() { if (IsGameObject()) return reinterpret_cast<GameObject*>(this); else return nullptr; }
|
||||
GameObject const* ToGameObject() const { if (IsGameObject()) return reinterpret_cast<GameObject const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; }
|
||||
static Corpse* ToCorpse(Object* o) { return o ? o->ToCorpse() : nullptr; }
|
||||
static Corpse const* ToCorpse(Object const* o) { return o ? o->ToCorpse() : nullptr; }
|
||||
Corpse* ToCorpse() { if (IsCorpse()) return reinterpret_cast<Corpse*>(this); else return nullptr; }
|
||||
Corpse const* ToCorpse() const { if (IsCorpse()) return reinterpret_cast<Corpse const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsDynObject() const { return GetTypeId() == TYPEID_DYNAMICOBJECT; }
|
||||
static DynamicObject* ToDynObject(Object* o) { return o ? o->ToDynObject() : nullptr; }
|
||||
static DynamicObject const* ToDynObject(Object const* o) { return o ? o->ToDynObject() : nullptr; }
|
||||
DynamicObject* ToDynObject() { if (IsDynObject()) return reinterpret_cast<DynamicObject*>(this); else return nullptr; }
|
||||
DynamicObject const* ToDynObject() const { if (IsDynObject()) return reinterpret_cast<DynamicObject const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsAreaTrigger() const { return GetTypeId() == TYPEID_AREATRIGGER; }
|
||||
static AreaTrigger* ToAreaTrigger(Object* o) { return o ? o->ToAreaTrigger() : nullptr; }
|
||||
static AreaTrigger const* ToAreaTrigger(Object const* o) { return o ? o->ToAreaTrigger() : nullptr; }
|
||||
AreaTrigger* ToAreaTrigger() { if (IsAreaTrigger()) return reinterpret_cast<AreaTrigger*>(this); else return nullptr; }
|
||||
AreaTrigger const* ToAreaTrigger() const { if (IsAreaTrigger()) return reinterpret_cast<AreaTrigger const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsSceneObject() const { return GetTypeId() == TYPEID_SCENEOBJECT; }
|
||||
static SceneObject* ToSceneObject(Object* o) { return o ? o->ToSceneObject() : nullptr; }
|
||||
static SceneObject const* ToSceneObject(Object const* o) { return o ? o->ToSceneObject() : nullptr; }
|
||||
SceneObject* ToSceneObject() { if (IsSceneObject()) return reinterpret_cast<SceneObject*>(this); else return nullptr; }
|
||||
SceneObject const* ToSceneObject() const { if (IsSceneObject()) return reinterpret_cast<SceneObject const*>(this); else return nullptr; }
|
||||
|
||||
inline bool IsConversation() const { return GetTypeId() == TYPEID_CONVERSATION; }
|
||||
static Conversation* ToConversation(Object* o) { return o ? o->ToConversation() : nullptr; }
|
||||
static Conversation const* ToConversation(Object const* o) { return o ? o->ToConversation() : nullptr; }
|
||||
Conversation* ToConversation() { if (IsConversation()) return reinterpret_cast<Conversation*>(this); else return nullptr; }
|
||||
Conversation const* ToConversation() const { if (IsConversation()) return reinterpret_cast<Conversation const*>(this); else return nullptr; }
|
||||
|
||||
friend UF::UpdateFieldHolder;
|
||||
UF::UpdateFieldHolder m_values;
|
||||
UF::UpdateField<UF::ObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_OBJECT> m_objectData;
|
||||
|
||||
template<typename T>
|
||||
void ForceUpdateFieldChange(UF::UpdateFieldPrivateSetter<T> const& /*setter*/)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
|
||||
virtual std::string GetDebugInfo() const;
|
||||
std::string GetDebugInfo() const override;
|
||||
|
||||
Trinity::unique_weak_ptr<Object> GetWeakPtr() const { return m_scriptRef; }
|
||||
|
||||
@@ -330,242 +173,19 @@ class TC_GAME_API Object
|
||||
protected:
|
||||
Object();
|
||||
|
||||
void _Create(ObjectGuid const& guid);
|
||||
|
||||
template<typename T>
|
||||
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
|
||||
{
|
||||
if (UF::SetUpdateFieldValue(setter, std::move(value)))
|
||||
AddToObjectUpdateIfNeeded();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SetUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "SetUpdateFieldFlagValue must be used with integral types");
|
||||
SetUpdateFieldValue(setter, setter.GetValue() | flag);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveUpdateFieldFlagValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type flag)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "RemoveUpdateFieldFlagValue must be used with integral types");
|
||||
SetUpdateFieldValue(setter, setter.GetValue() & ~flag);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename UF::DynamicUpdateFieldSetter<T>::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
return UF::AddDynamicUpdateFieldValue(setter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename UF::DynamicUpdateFieldSetter<T>::insert_result InsertDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
return UF::InsertDynamicUpdateFieldValue(setter, index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter<T> setter, uint32 index)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveDynamicUpdateFieldValue(setter, index);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
void RemoveMapUpdateFieldValue(UF::MapUpdateFieldSetter<K, V> setter, std::type_identity_t<K> const& key)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveMapUpdateFieldValue(setter, key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::ClearDynamicUpdateFieldValues(setter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter<T> setter)
|
||||
{
|
||||
AddToObjectUpdateIfNeeded();
|
||||
UF::RemoveOptionalUpdateFieldValue(setter);
|
||||
}
|
||||
|
||||
// stat system helpers
|
||||
template<typename T>
|
||||
void SetUpdateFieldStatValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type value)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
SetUpdateFieldValue(setter, std::max(value, T(0)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ApplyModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, typename UF::UpdateFieldPrivateSetter<T>::value_type mod, bool apply)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
|
||||
T value = setter.GetValue();
|
||||
if (apply)
|
||||
value += mod;
|
||||
else
|
||||
value -= mod;
|
||||
|
||||
SetUpdateFieldValue(setter, value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldPrivateSetter<T> setter, float percent, bool apply)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "SetUpdateFieldStatValue must be used with arithmetic types");
|
||||
|
||||
T value = setter.GetValue();
|
||||
|
||||
// don't want to include Util.h here
|
||||
//ApplyPercentModFloatVar(value, percent, apply);
|
||||
if (percent == -100.0f)
|
||||
percent = -99.99f;
|
||||
value *= (apply ? (100.0f + percent) / 100.0f : 100.0f / (100.0f + percent));
|
||||
|
||||
SetUpdateFieldValue(setter, value);
|
||||
}
|
||||
|
||||
template<typename Action>
|
||||
void DoWithSuppressingObjectUpdates(Action&& action)
|
||||
{
|
||||
bool wasUpdatedBeforeAction = m_objectUpdated;
|
||||
action();
|
||||
if (m_objectUpdated && !wasUpdatedBeforeAction)
|
||||
{
|
||||
RemoveFromObjectUpdate();
|
||||
m_objectUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Player const* target) const;
|
||||
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const* target) const;
|
||||
virtual void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const = 0;
|
||||
virtual void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const = 0;
|
||||
static void BuildEntityFragments(ByteBuffer* data, std::span<WowCS::EntityFragment const> fragments);
|
||||
void 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;
|
||||
void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer* data, EnumFlag<UF::UpdateFieldFlag> flags) const;
|
||||
|
||||
public:
|
||||
virtual void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const;
|
||||
|
||||
protected:
|
||||
TypeID m_objectTypeId;
|
||||
CreateObjectBits m_updateFlag;
|
||||
WowCS::EntityFragmentsHolder m_entityFragments;
|
||||
|
||||
virtual bool AddToObjectUpdate() = 0;
|
||||
virtual void RemoveFromObjectUpdate() = 0;
|
||||
void AddToObjectUpdateIfNeeded();
|
||||
|
||||
bool m_objectUpdated;
|
||||
|
||||
private:
|
||||
bool m_inWorld;
|
||||
bool m_isNewObject;
|
||||
bool m_isDestroyedObject;
|
||||
|
||||
struct NoopObjectDeleter { void operator()(Object*) const { /*noop - not managed*/ } };
|
||||
Trinity::unique_trackable_ptr<Object> m_scriptRef;
|
||||
|
||||
Object(Object const& right) = delete;
|
||||
Object(Object&& right) = delete;
|
||||
Object& operator=(Object const& right) = delete;
|
||||
Object& operator=(Object&& right) = delete;
|
||||
};
|
||||
|
||||
inline Object* UF::UpdateFieldHolder::GetOwner()
|
||||
{
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<Object*>(reinterpret_cast<std::byte*>(this) - offsetof(Object, m_values));
|
||||
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(UpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
Object* owner = GetOwner();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
return { (static_cast<Derived*>(owner)->*field)._value };
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline UF::OptionalUpdateFieldSetter<T> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
Object* owner = GetOwner();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
return { static_cast<Derived*>(owner)->*field };
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline UF::MutableFieldReference<T, false> UF::UpdateFieldHolder::ModifyValue(OptionalUpdateField<T, BlockBit, Bit> Derived::* field, uint32 /*dummy*/)
|
||||
{
|
||||
Object* owner = GetOwner();
|
||||
owner->m_entityFragments.ContentsChangedMask |= owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
_changesMask |= UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
|
||||
auto& uf = (static_cast<Derived*>(owner)->*field);
|
||||
if (!uf.has_value())
|
||||
uf.ConstructValue();
|
||||
|
||||
return { *uf._value };
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void UF::UpdateFieldHolder::ClearChangesMask(UpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
Object* owner = GetOwner();
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
{
|
||||
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
if (!_changesMask)
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
}
|
||||
else
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
|
||||
(static_cast<Derived*>(owner)->*field)._value.ClearChangesMask();
|
||||
}
|
||||
|
||||
template <typename Derived, typename T, int32 BlockBit, uint32 Bit>
|
||||
inline void UF::UpdateFieldHolder::ClearChangesMask(OptionalUpdateField<T, BlockBit, Bit> Derived::* field)
|
||||
{
|
||||
Object* owner = GetOwner();
|
||||
if constexpr (WowCS::EntityFragment(BlockBit) == WowCS::EntityFragment::CGObject)
|
||||
{
|
||||
_changesMask &= ~UpdateMaskHelpers::GetBlockFlag(Bit);
|
||||
if (!_changesMask)
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
}
|
||||
else
|
||||
owner->m_entityFragments.ContentsChangedMask &= ~owner->m_entityFragments.GetUpdateMaskFor(WowCS::EntityFragment(BlockBit));
|
||||
|
||||
auto& uf = (static_cast<Derived*>(owner)->*field);
|
||||
if (uf.has_value())
|
||||
uf._value->ClearChangesMask();
|
||||
}
|
||||
|
||||
template <class T_VALUES, class T_FLAGS, class FLAG_TYPE, size_t ARRAY_SIZE>
|
||||
class FlaggedValuesArray32
|
||||
{
|
||||
|
||||
@@ -81,7 +81,7 @@ enum TypeMask
|
||||
TYPEMASK_WORLDOBJECT = TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE | TYPEMASK_AREATRIGGER | TYPEMASK_SCENEOBJECT | TYPEMASK_CONVERSATION
|
||||
};
|
||||
|
||||
inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES> ObjectTypeMask =
|
||||
inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES + 1> ObjectTypeMask =
|
||||
{
|
||||
TYPEMASK_OBJECT,
|
||||
TYPEMASK_OBJECT | TYPEMASK_ITEM,
|
||||
@@ -101,6 +101,7 @@ inline constexpr std::array<uint32, NUM_CLIENT_OBJECT_TYPES> ObjectTypeMask =
|
||||
TYPEMASK_OBJECT | TYPEMASK_AI_GROUP,
|
||||
TYPEMASK_OBJECT | TYPEMASK_SCENARIO,
|
||||
TYPEMASK_OBJECT | TYPEMASK_LOOT_OBJECT,
|
||||
0,
|
||||
};
|
||||
|
||||
enum class HighGuid
|
||||
|
||||
@@ -1683,7 +1683,7 @@ bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry, uint32 /*p
|
||||
SetMap(map);
|
||||
|
||||
// TODO: counter should be constructed as (summon_count << 32) | petNumber
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Pet>(map->GetId(), Entry, guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Pet>(map->GetId(), Entry, guidlow));
|
||||
|
||||
m_spawnId = guidlow;
|
||||
m_originalEntry = Entry;
|
||||
|
||||
@@ -387,7 +387,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
|
||||
//FIXME: outfitId not used in player creating
|
||||
/// @todo need more checks against packet modifications
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Player>(guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Player>(guidlow));
|
||||
|
||||
m_name = createInfo->Name;
|
||||
|
||||
@@ -17856,7 +17856,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(guid);
|
||||
_Create(guid);
|
||||
|
||||
m_name = std::move(fields.name);
|
||||
|
||||
@@ -24097,7 +24097,7 @@ uint8 Player::GetStartLevel(uint8 race, uint8 playerClass, Optional<int32> chara
|
||||
return startLevel;
|
||||
}
|
||||
|
||||
bool Player::HaveAtClient(Object const* u) const
|
||||
bool Player::HaveAtClient(BaseEntity const* u) const
|
||||
{
|
||||
return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end();
|
||||
}
|
||||
|
||||
@@ -2631,7 +2631,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
|
||||
GuidUnorderedSet m_clientGUIDs;
|
||||
GuidUnorderedSet m_visibleTransports;
|
||||
|
||||
bool HaveAtClient(Object const* u) const;
|
||||
bool HaveAtClient(BaseEntity const* u) const;
|
||||
|
||||
bool IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects = false) const override;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ bool SceneObject::Create(ObjectGuid::LowType lowGuid, SceneType type, uint32 sce
|
||||
|
||||
SetPrivateObjectOwner(privateObjectOwner);
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::SceneObject>(GetMapId(), sceneId, lowGuid));
|
||||
_Create(ObjectGuid::Create<HighGuid::SceneObject>(GetMapId(), sceneId, lowGuid));
|
||||
PhasingHandler::InheritPhaseShift(this, creator);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
@@ -107,7 +107,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float
|
||||
return false;
|
||||
}
|
||||
|
||||
Object::_Create(ObjectGuid::Create<HighGuid::Transport>(guidlow));
|
||||
_Create(ObjectGuid::Create<HighGuid::Transport>(guidlow));
|
||||
|
||||
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
|
||||
if (!goinfo)
|
||||
|
||||
Reference in New Issue
Block a user