diff options
| author | Shauren <shauren.trinity@gmail.com> | 2025-08-13 00:31:39 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2025-08-13 00:31:39 +0200 |
| commit | 5cf0c6c8bb2c4e58a2d66ba5f304af34d18a4782 (patch) | |
| tree | 0616f3e83f511aae0e10916f0c22161017e09c24 /src/server/game/Entities | |
| parent | 82f19c898815e3bc5bb6288b0191ee897594f9b5 (diff) | |
Core: Updated to 11.2.0
Diffstat (limited to 'src/server/game/Entities')
17 files changed, 2285 insertions, 1336 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 868ad6fbbc1..f1bff65dc63 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -24,6 +24,8 @@ #include "Containers.h" #include "CreatureAISelector.h" #include "DB2Stores.h" +#include "G3DPosition.hpp" +#include "GameTime.h" #include "GridNotifiersImpl.h" #include "Language.h" #include "Log.h" @@ -46,15 +48,14 @@ #include <bit> AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr), - _duration(0), _totalDuration(0), _timeSinceCreated(0), _verticesUpdatePreviousOrientation(std::numeric_limits<float>::infinity()), - _isRemoved(false), _reachedDestination(true), _lastSplineIndex(0), _movementTime(0), + _duration(0), _totalDuration(0), _verticesUpdatePreviousOrientation(std::numeric_limits<float>::infinity()), + _isRemoved(false), _reachedDestination(true), _lastSplineIndex(0), _areaTriggerCreateProperties(nullptr), _areaTriggerTemplate(nullptr) { m_objectType |= TYPEMASK_AREATRIGGER; m_objectTypeId = TYPEID_AREATRIGGER; m_updateFlag.Stationary = true; - m_updateFlag.AreaTrigger = true; m_entityFragments.Add(WowCS::EntityFragment::Tag_AreaTrigger, false); } @@ -146,7 +147,7 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti SetObjectScale(1.0f); SetDuration(duration); - _shape = GetCreateProperties()->Shape; + SetShape(GetCreateProperties()->Shape); auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); if (caster) @@ -199,6 +200,33 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti if (GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::VisualAnimIsDecay)) SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::IsDecay), true); + AreaTriggerFieldFlags fieldFlags = [flags = GetCreateProperties()->Flags]() + { + AreaTriggerFieldFlags fieldFlags = AreaTriggerFieldFlags::None; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation)) + fieldFlags |= AreaTriggerFieldFlags::AbsoluteOrientation; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasDynamicShape)) + fieldFlags |= AreaTriggerFieldFlags::DynamicShape; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached)) + fieldFlags |= AreaTriggerFieldFlags::Attached; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFaceMovementDir)) + fieldFlags |= AreaTriggerFieldFlags::FaceMovementDir; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFollowsTerrain)) + fieldFlags |= AreaTriggerFieldFlags::FollowsTerrain; + if (flags.HasFlag(AreaTriggerCreatePropertiesFlag::AlwaysExterior)) + fieldFlags |= AreaTriggerFieldFlags::AlwaysExterior; + return fieldFlags; + }(); + ReplaceAllAreaTriggerFlags(fieldFlags); + + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MovementStartTime), GameTime::GetGameTimeMS()); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::CreationTime), GameTime::GetGameTimeMS()); + + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ScaleCurveId), GetCreateProperties()->ScaleCurveId); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::FacingCurveId), GetCreateProperties()->FacingCurveId); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MorphCurveId), GetCreateProperties()->MorphCurveId); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MoveCurveId), GetCreateProperties()->MoveCurveId); + if (caster) PhasingHandler::InheritPhaseShift(this, caster); else if (IsStaticSpawn() && spawnData) @@ -207,7 +235,7 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti PhasingHandler::InitDbPhaseShift(GetPhaseShift(), spawnData->phaseUseFlags, spawnData->phaseId, spawnData->phaseGroup); } - if (target && GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached)) + if (target && HasAreaTriggerFlag(AreaTriggerFieldFlags::Attached)) m_movementInfo.transport.guid = target->GetGUID(); if (!IsStaticSpawn()) @@ -218,7 +246,7 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti if (GetCreateProperties()->OrbitInfo) { AreaTriggerOrbitInfo orbit = *GetCreateProperties()->OrbitInfo; - if (target && GetCreateProperties() && GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached)) + if (target && HasAreaTriggerFlag(AreaTriggerFieldFlags::Attached)) orbit.PathTarget = target->GetGUID(); else orbit.Center = pos; @@ -229,6 +257,10 @@ bool AreaTrigger::Create(AreaTriggerCreatePropertiesId areaTriggerCreateProperti { InitSplineOffsets(GetCreateProperties()->SplinePoints); } + else + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), int32(AreaTriggerPathType::None)); + + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::Facing), _stationaryPosition.GetOrientation()); // movement on transport of areatriggers on unit is handled by themself TransportBase* transport = nullptr; @@ -307,7 +339,6 @@ bool AreaTrigger::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool /*addTo void AreaTrigger::Update(uint32 diff) { WorldObject::Update(diff); - _timeSinceCreated += diff; if (!IsStaticSpawn()) { @@ -318,18 +349,17 @@ void AreaTrigger::Update(uint32 diff) } else if (HasOrbit()) { - UpdateOrbitPosition(*std::get<std::unique_ptr<AreaTriggerOrbitInfo>>(_movement), diff); + UpdateOrbitPosition(); } - else if (GetCreateProperties() && GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached)) + else if (HasAreaTriggerFlag(AreaTriggerFieldFlags::Attached)) { if (Unit* target = GetTarget()) { float orientation = 0.0f; - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->FacingCurveId) - orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress()); + if (m_areaTriggerData->FacingCurveId) + orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress()); - if (!GetCreateProperties() || !GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation)) + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::AbsoluteOrientation)) orientation += target->GetOrientation(); GetMap()->AreaTriggerRelocation(this, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), orientation); @@ -337,20 +367,17 @@ void AreaTrigger::Update(uint32 diff) } else if (HasSplines()) { - UpdateSplinePosition(*std::get<std::unique_ptr<::Movement::Spline<float>>>(_movement), diff); + UpdateSplinePosition(*_spline); } else { - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) + if (m_areaTriggerData->FacingCurveId) { - if (createProperties->FacingCurveId) - { - float orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress()); - if (!GetCreateProperties() || !GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation)) - orientation += _stationaryPosition.GetOrientation(); + float orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress()); + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::AbsoluteOrientation)) + orientation += m_areaTriggerData->Facing; - SetOrientation(orientation); - } + SetOrientation(orientation); } UpdateShape(); @@ -381,6 +408,14 @@ void AreaTrigger::Remove() } } +uint32 AreaTrigger::GetTimeSinceCreated() const +{ + uint32 now = GameTime::GetGameTimeMS(); + if (now >= *m_areaTriggerData->CreationTime) + return now - *m_areaTriggerData->CreationTime; + return 0; +} + void AreaTrigger::SetOverrideScaleCurve(float overrideScale) { SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale); @@ -467,9 +502,8 @@ float AreaTrigger::CalcCurrentScale() const float scale = 1.0f; if (m_areaTriggerData->OverrideScaleCurve->OverrideActive) scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale), 0.000001f); - else if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->ScaleCurveId) - scale *= std::max(sDB2Manager.GetCurveValueAt(createProperties->ScaleCurveId, GetScaleCurveProgress(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale)), 0.000001f); + else if (m_areaTriggerData->ScaleCurveId) + scale *= std::max(sDB2Manager.GetCurveValueAt(m_areaTriggerData->ScaleCurveId, GetScaleCurveProgress(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale)), 0.000001f); scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->ExtraScaleCurve, m_areaTriggerData->TimeToTargetExtraScale), 0.000001f); @@ -609,29 +643,21 @@ void AreaTrigger::UpdateTargetList() { std::vector<Unit*> targetList; - switch (_shape.Type) + m_areaTriggerData->ShapeData.Visit([&]<typename ShapeType>(ShapeType const& shape) { - case AreaTriggerShapeType::Sphere: - SearchUnitInSphere(targetList); - break; - case AreaTriggerShapeType::Box: - SearchUnitInBox(targetList); - break; - case AreaTriggerShapeType::Polygon: - SearchUnitInPolygon(targetList); - break; - case AreaTriggerShapeType::Cylinder: - SearchUnitInCylinder(targetList); - break; - case AreaTriggerShapeType::Disk: - SearchUnitInDisk(targetList); - break; - case AreaTriggerShapeType::BoundedPlane: - SearchUnitInBoundedPlane(targetList); - break; - default: - break; - } + if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerSphere>) + this->SearchUnitInSphere(shape, targetList); + else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBox>) + this->SearchUnitInBox(shape, targetList); + else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerPolygon>) + this->SearchUnitInPolygon(shape, targetList); + else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerCylinder>) + this->SearchUnitInCylinder(shape, targetList); + else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerDisk>) + this->SearchUnitInDisk(shape, targetList); + else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBoundedPlane>) + this->SearchUnitInBoundedPlane(shape, targetList); + }); if (GetTemplate()) { @@ -704,30 +730,28 @@ void AreaTrigger::SearchUnits(std::vector<Unit*>& targetList, float radius, bool } } -void AreaTrigger::SearchUnitInSphere(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInSphere(UF::AreaTriggerSphere const& sphere, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); float scale = CalcCurrentScale(); - float radius = G3D::lerp(_shape.SphereDatas.Radius, _shape.SphereDatas.RadiusTarget, progress) * scale; + float radius = G3D::lerp(sphere.Radius, sphere.RadiusTarget, progress) * scale; SearchUnits(targetList, radius, true); } -void AreaTrigger::SearchUnitInBox(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInBox(UF::AreaTriggerBox const& box, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); float scale = CalcCurrentScale(); - float extentsX = G3D::lerp(_shape.BoxDatas.Extents[0], _shape.BoxDatas.ExtentsTarget[0], progress) * scale; - float extentsY = G3D::lerp(_shape.BoxDatas.Extents[1], _shape.BoxDatas.ExtentsTarget[1], progress) * scale; - float extentsZ = G3D::lerp(_shape.BoxDatas.Extents[2], _shape.BoxDatas.ExtentsTarget[2], progress) * scale; + float extentsX = G3D::lerp(box.Extents->Pos.GetPositionX(), box.ExtentsTarget->Pos.GetPositionX(), progress) * scale; + float extentsY = G3D::lerp(box.Extents->Pos.GetPositionY(), box.ExtentsTarget->Pos.GetPositionY(), progress) * scale; + float extentsZ = G3D::lerp(box.Extents->Pos.GetPositionZ(), box.ExtentsTarget->Pos.GetPositionZ(), progress) * scale; float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY); SearchUnits(targetList, radius, false); @@ -739,14 +763,13 @@ void AreaTrigger::SearchUnitInBox(std::vector<Unit*>& targetList) }); } -void AreaTrigger::SearchUnitInPolygon(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInPolygon(UF::AreaTriggerPolygon const& polygon, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); - float height = G3D::lerp(_shape.PolygonDatas.Height, _shape.PolygonDatas.HeightTarget, progress); + float height = G3D::lerp(polygon.Height, polygon.HeightTarget, progress); float minZ = GetPositionZ() - height; float maxZ = GetPositionZ() + height; @@ -760,17 +783,16 @@ void AreaTrigger::SearchUnitInPolygon(std::vector<Unit*>& targetList) }); } -void AreaTrigger::SearchUnitInCylinder(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInCylinder(UF::AreaTriggerCylinder const& cylinder, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); float scale = CalcCurrentScale(); - float radius = G3D::lerp(_shape.CylinderDatas.Radius, _shape.CylinderDatas.RadiusTarget, progress) * scale; - float height = G3D::lerp(_shape.CylinderDatas.Height, _shape.CylinderDatas.HeightTarget, progress); - if (!m_areaTriggerData->HeightIgnoresScale) + float radius = G3D::lerp(cylinder.Radius, cylinder.RadiusTarget, progress) * scale; + float height = G3D::lerp(cylinder.Height, cylinder.HeightTarget, progress); + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::HeightIgnoresScale)) height *= scale; float minZ = GetPositionZ() - height; @@ -785,18 +807,17 @@ void AreaTrigger::SearchUnitInCylinder(std::vector<Unit*>& targetList) }); } -void AreaTrigger::SearchUnitInDisk(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); float scale = CalcCurrentScale(); - float innerRadius = G3D::lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress) * scale; - float outerRadius = G3D::lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress) * scale; - float height = G3D::lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress); - if (!m_areaTriggerData->HeightIgnoresScale) + float innerRadius = G3D::lerp(disk.InnerRadius, disk.InnerRadiusTarget, progress) * scale; + float outerRadius = G3D::lerp(disk.OuterRadius, disk.OuterRadiusTarget, progress) * scale; + float height = G3D::lerp(disk.Height, disk.HeightTarget, progress); + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::HeightIgnoresScale)) height *= scale; float minZ = GetPositionZ() - height; @@ -810,16 +831,15 @@ void AreaTrigger::SearchUnitInDisk(std::vector<Unit*>& targetList) }); } -void AreaTrigger::SearchUnitInBoundedPlane(std::vector<Unit*>& targetList) +void AreaTrigger::SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector<Unit*>& targetList) { float progress = GetProgress(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); float scale = CalcCurrentScale(); - float extentsX = G3D::lerp(_shape.BoundedPlaneDatas.Extents[0], _shape.BoundedPlaneDatas.ExtentsTarget[0], progress) * scale; - float extentsY = G3D::lerp(_shape.BoundedPlaneDatas.Extents[1], _shape.BoundedPlaneDatas.ExtentsTarget[1], progress) * scale; + float extentsX = G3D::lerp(boundedPlane.Extents->Pos.GetPositionX(), boundedPlane.ExtentsTarget->Pos.GetPositionX(), progress) * scale; + float extentsY = G3D::lerp(boundedPlane.Extents->Pos.GetPositionY(), boundedPlane.ExtentsTarget->Pos.GetPositionY(), progress) * scale; float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY); SearchUnits(targetList, radius, false); @@ -885,9 +905,10 @@ void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList) } } - SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::NumUnitsInside), _insideUnits.size()); - SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::NumPlayersInside), - std::ranges::count_if(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); })); + if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); })) + SetAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); + else + RemoveAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); if (IsStaticSpawn()) setActive(!_insideUnits.empty()); @@ -928,6 +949,83 @@ uint32 AreaTrigger::GetFaction() const return 0; } +void AreaTrigger::SetShape(AreaTriggerShapeInfo const& shape) +{ + auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); + + switch (shape.Type) + { + case AreaTriggerShapeType::Sphere: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 0); + auto sphere = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerSphere>); + SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::Radius), shape.SphereDatas.Radius); + SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::RadiusTarget), shape.SphereDatas.RadiusTarget); + break; + } + case AreaTriggerShapeType::Box: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 1); + auto box = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBox>); + SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::Extents), { shape.BoxDatas.Extents[0], shape.BoxDatas.Extents[1], shape.BoxDatas.Extents[2] }); + SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::ExtentsTarget), { shape.BoxDatas.ExtentsTarget[0], shape.BoxDatas.ExtentsTarget[1], shape.BoxDatas.ExtentsTarget[2] }); + break; + } + case AreaTriggerShapeType::Polygon: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 3); + auto polygon = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerPolygon>); + auto vertices = polygon.ModifyValue(&UF::AreaTriggerPolygon::Vertices); + ClearDynamicUpdateFieldValues(vertices); + for (TaggedPosition<XY> const& vertex : shape.PolygonVertices) + AddDynamicUpdateFieldValue(vertices) = vertex; + auto verticesTarget = polygon.ModifyValue(&UF::AreaTriggerPolygon::VerticesTarget); + ClearDynamicUpdateFieldValues(verticesTarget); + for (TaggedPosition<XY> const& vertex : shape.PolygonVerticesTarget) + AddDynamicUpdateFieldValue(verticesTarget) = vertex; + SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::Height), shape.PolygonDatas.Height); + SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::HeightTarget), shape.PolygonDatas.HeightTarget); + break; + } + case AreaTriggerShapeType::Cylinder: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 4); + auto cylinder = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerCylinder>); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Radius), shape.CylinderDatas.Radius); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::RadiusTarget), shape.CylinderDatas.RadiusTarget); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Height), shape.CylinderDatas.Height); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::HeightTarget), shape.CylinderDatas.HeightTarget); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffset), shape.CylinderDatas.LocationZOffset); + SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffsetTarget), shape.CylinderDatas.LocationZOffsetTarget); + break; + } + case AreaTriggerShapeType::Disk: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 7); + auto disk = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerDisk>); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadius), shape.DiskDatas.InnerRadius); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadiusTarget), shape.DiskDatas.InnerRadiusTarget); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadius), shape.DiskDatas.OuterRadius); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadiusTarget), shape.DiskDatas.OuterRadiusTarget); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::Height), shape.DiskDatas.Height); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::HeightTarget), shape.DiskDatas.HeightTarget); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffset), shape.DiskDatas.LocationZOffset); + SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffsetTarget), shape.DiskDatas.LocationZOffsetTarget); + break; + } + case AreaTriggerShapeType::BoundedPlane: + { + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 8); + auto boundedPlane = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBoundedPlane>); + SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::Extents), { shape.BoundedPlaneDatas.Extents[0], shape.BoundedPlaneDatas.Extents[1] }); + SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsTarget), { shape.BoundedPlaneDatas.ExtentsTarget[0], shape.BoundedPlaneDatas.ExtentsTarget[1] }); + break; + } + default: + break; + } +} + float AreaTrigger::GetMaxSearchRadius() const { return *m_areaTriggerData->BoundsRadius2D * CalcCurrentScale(); @@ -935,25 +1033,24 @@ float AreaTrigger::GetMaxSearchRadius() const void AreaTrigger::UpdatePolygonVertices() { - AreaTriggerCreateProperties const* createProperties = GetCreateProperties(); - AreaTriggerShapeInfo const& shape = GetShape(); + UF::AreaTriggerPolygon const* shape = m_areaTriggerData->ShapeData.Get<UF::AreaTriggerPolygon>(); float newOrientation = GetOrientation(); // No need to recalculate, orientation didn't change - if (G3D::fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && shape.PolygonVerticesTarget.empty()) + if (G3D::fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && shape->VerticesTarget.empty()) return; - _polygonVertices.assign(shape.PolygonVertices.begin(), shape.PolygonVertices.end()); - if (!shape.PolygonVerticesTarget.empty()) + _polygonVertices.assign(shape->Vertices.begin(), shape->Vertices.end()); + if (!shape->VerticesTarget.empty()) { float progress = GetProgress(); - if (createProperties->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress); + if (m_areaTriggerData->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress); for (std::size_t i = 0; i < _polygonVertices.size(); ++i) { Position& vertex = _polygonVertices[i]; - Position const& vertexTarget = shape.PolygonVerticesTarget[i].Pos; + Position const& vertexTarget = shape->VerticesTarget[i].Pos; vertex.m_positionX = G3D::lerp(vertex.GetPositionX(), vertexTarget.GetPositionX(), progress); vertex.m_positionY = G3D::lerp(vertex.GetPositionY(), vertexTarget.GetPositionY(), progress); @@ -983,7 +1080,7 @@ bool AreaTrigger::HasOverridePosition() const void AreaTrigger::UpdateShape() { - if (_shape.IsPolygon()) + if (m_areaTriggerData->ShapeData.Is<UF::AreaTriggerPolygon>()) UpdatePolygonVertices(); } @@ -1120,8 +1217,6 @@ void AreaTrigger::InitSplines(std::vector<G3D::Vector3> const& splinePoints, Opt if (splinePoints.size() < 2) return; - _movementTime = 0; - std::unique_ptr<Movement::Spline<float>> spline = std::make_unique<::Movement::Spline<float>>(); spline->init_spline(splinePoints.data(), splinePoints.size(), ::Movement::SplineBase::ModeLinear, _stationaryPosition.GetOrientation()); spline->initLengths(); @@ -1131,29 +1226,29 @@ void AreaTrigger::InitSplines(std::vector<G3D::Vector3> const& splinePoints, Opt speed = 1.0f; uint32 timeToTarget = spline->length() / speed * float(IN_MILLISECONDS); - SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); - - if (IsInWorld()) - { - if (_reachedDestination) - { - WorldPackets::AreaTrigger::AreaTriggerRePath reshape; - reshape.TriggerGUID = GetGUID(); - SendMessageToSet(reshape.Write(), true); - } - WorldPackets::AreaTrigger::AreaTriggerRePath reshape; - reshape.TriggerGUID = GetGUID(); - reshape.AreaTriggerSpline.emplace(); - reshape.AreaTriggerSpline->ElapsedTimeForMovement = GetElapsedTimeForMovement(); - reshape.AreaTriggerSpline->TimeToTarget = timeToTarget; - reshape.AreaTriggerSpline->Points = spline.get(); + auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MovementStartTime), GameTime::GetGameTimeMS()); - SendMessageToSet(reshape.Write(), true); - } + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathType), int32(AreaTriggerPathType::Spline)); + auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerSplineCalculator>); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerSplineCalculator::Catmullrom), spline->getPointCount() >= 4); + auto points = pathData.ModifyValue(&UF::AreaTriggerSplineCalculator::Points); + ClearDynamicUpdateFieldValues(points); + for (G3D::Vector3 const& point : spline->getPoints()) + AddDynamicUpdateFieldValue(points) = Vector3ToPosition(point); _reachedDestination = false; - _movement = std::move(spline); + _spline = std::move(spline); +} + +uint32 AreaTrigger::GetElapsedTimeForMovement() const +{ + uint32 now = GameTime::GetGameTimeMS(); + if (now >= *m_areaTriggerData->MovementStartTime) + return now - *m_areaTriggerData->MovementStartTime; + return 0; } void AreaTrigger::InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional<float> overrideSpeed) @@ -1167,40 +1262,37 @@ void AreaTrigger::InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional<float> o uint32 timeToTarget = static_cast<uint32>(orbit.Radius * 2.0f * static_cast<float>(M_PI) * static_cast<float>(IN_MILLISECONDS) / speed); - SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); - SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OrbitPathTarget), orbit.PathTarget.value_or(ObjectGuid::Empty)); - - std::unique_ptr<AreaTriggerOrbitInfo> movementOrbit = std::make_unique<AreaTriggerOrbitInfo>(); - - movementOrbit->TimeToTarget = timeToTarget; - movementOrbit->ElapsedTimeForMovement = 0; - - if (IsInWorld()) - { - WorldPackets::AreaTrigger::AreaTriggerRePath reshape; - reshape.TriggerGUID = GetGUID(); - reshape.AreaTriggerOrbit = *movementOrbit; - - SendMessageToSet(reshape.Write(), true); - } + auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MovementStartTime), GameTime::GetGameTimeMS()); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OrbitPathTarget), orbit.PathTarget.value_or(ObjectGuid::Empty)); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ZOffset), orbit.ZOffset); + if (orbit.CanLoop) + SetAreaTriggerFlag(AreaTriggerFieldFlags::CanLoop); + else + RemoveAreaTriggerFlag(AreaTriggerFieldFlags::CanLoop); - _movement = std::move(movementOrbit); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathType), int32(AreaTriggerPathType::Orbit)); + auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerOrbit>); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::CounterClockwise), orbit.CounterClockwise); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Center), orbit.Center.value_or(Position())); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Radius), orbit.Radius); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::InitialAngle), orbit.InitialAngle); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::BlendFromRadius), orbit.BlendFromRadius); + SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::ExtraTimeForBlending), orbit.ExtraTimeForBlending); } Position const* AreaTrigger::GetOrbitCenterPosition() const { - if (!HasOrbit()) + UF::AreaTriggerOrbit const* orbit = m_areaTriggerData->PathData.Get<UF::AreaTriggerOrbit>(); + if (!orbit) return nullptr; - AreaTriggerOrbitInfo const& orbit = *std::get<std::unique_ptr<AreaTriggerOrbitInfo>>(_movement); - if (orbit.PathTarget) - if (WorldObject* center = ObjectAccessor::GetWorldObject(*this, *orbit.PathTarget)) + if (!m_areaTriggerData->OrbitPathTarget->IsEmpty()) + if (WorldObject* center = ObjectAccessor::GetWorldObject(*this, *m_areaTriggerData->OrbitPathTarget)) return center; - if (orbit.Center) - return &orbit.Center->Pos; - - return nullptr; + return &orbit->Center->Pos; } Position AreaTrigger::CalculateOrbitPosition() const @@ -1209,26 +1301,24 @@ Position AreaTrigger::CalculateOrbitPosition() const if (!centerPos) return GetPosition(); - AreaTriggerCreateProperties const* createProperties = GetCreateProperties(); - AreaTriggerOrbitInfo const& cmi = GetOrbit(); + UF::AreaTriggerOrbit const& cmi = *m_areaTriggerData->PathData.Get<UF::AreaTriggerOrbit>(); // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time - float pathProgress = float(cmi.ElapsedTimeForMovement) / float(cmi.TimeToTarget); - if (createProperties && createProperties->MoveCurveId) - pathProgress = sDB2Manager.GetCurveValueAt(createProperties->MoveCurveId, pathProgress); + float pathProgress = float(GetElapsedTimeForMovement() + *cmi.ExtraTimeForBlending) / float(GetTimeToTarget()); + if (m_areaTriggerData->MoveCurveId) + pathProgress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, pathProgress); // We already made one circle and can't loop - if (!cmi.CanLoop) + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::CanLoop)) pathProgress = std::min(1.f, pathProgress); float radius = cmi.Radius; - if (G3D::fuzzyNe(cmi.BlendFromRadius, radius)) + if (pathProgress <= 1.0f && G3D::fuzzyNe(cmi.BlendFromRadius, radius)) { float blendCurve = (cmi.BlendFromRadius - radius) / radius; - // 4.f Defines four quarters - blendCurve = RoundToInterval(blendCurve, 1.f, 4.f) / 4.f; - float blendProgress = std::min(1.f, pathProgress / blendCurve); - radius = G3D::lerp(cmi.BlendFromRadius, cmi.Radius, blendProgress); + RoundToInterval(blendCurve, 1.f, 4.f); + float blendProgress = std::min(1.f, pathProgress / blendCurve * 0.63661975f); + radius = G3D::lerp(cmi.BlendFromRadius, radius, blendProgress); } // Adapt Path progress depending of circle direction @@ -1238,13 +1328,13 @@ Position AreaTrigger::CalculateOrbitPosition() const float angle = cmi.InitialAngle + 2.f * float(M_PI) * pathProgress; float x = centerPos->GetPositionX() + (radius * std::cos(angle)); float y = centerPos->GetPositionY() + (radius * std::sin(angle)); - float z = centerPos->GetPositionZ() + cmi.ZOffset; + float z = centerPos->GetPositionZ() + *m_areaTriggerData->ZOffset; float orientation = 0.0f; - if (createProperties && createProperties->FacingCurveId) - orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress()); + if (m_areaTriggerData->FacingCurveId) + orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress()); - if (!GetCreateProperties() || !GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation)) + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::AbsoluteOrientation)) { orientation += angle; orientation += cmi.CounterClockwise ? float(M_PI_4) : -float(M_PI_4); @@ -1253,13 +1343,8 @@ Position AreaTrigger::CalculateOrbitPosition() const return { x, y, z, orientation }; } -void AreaTrigger::UpdateOrbitPosition(AreaTriggerOrbitInfo& orbit, uint32 /*diff*/) +void AreaTrigger::UpdateOrbitPosition() { - if (orbit.StartDelay > GetElapsedTimeForMovement()) - return; - - orbit.ElapsedTimeForMovement = GetElapsedTimeForMovement() - orbit.StartDelay; - Position pos = CalculateOrbitPosition(); GetMap()->AreaTriggerRelocation(this, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); @@ -1268,14 +1353,12 @@ void AreaTrigger::UpdateOrbitPosition(AreaTriggerOrbitInfo& orbit, uint32 /*diff #endif } -void AreaTrigger::UpdateSplinePosition(Movement::Spline<float>& spline, uint32 diff) +void AreaTrigger::UpdateSplinePosition(Movement::Spline<float>& spline) { if (_reachedDestination) return; - _movementTime += diff; - - if (_movementTime >= GetTimeToTarget()) + if (GetElapsedTimeForMovement() >= GetTimeToTarget()) { _reachedDestination = true; _lastSplineIndex = int32(spline.last()); @@ -1291,19 +1374,19 @@ void AreaTrigger::UpdateSplinePosition(Movement::Spline<float>& spline, uint32 d return; } - float currentTimePercent = float(_movementTime) / float(GetTimeToTarget()); + float currentTimePercent = float(GetElapsedTimeForMovement()) / float(GetTimeToTarget()); if (currentTimePercent <= 0.f) return; - AreaTriggerCreateProperties const* createProperties = GetCreateProperties(); - if (createProperties && createProperties->MoveCurveId) + if (m_areaTriggerData->MoveCurveId) { - float progress = sDB2Manager.GetCurveValueAt(createProperties->MoveCurveId, currentTimePercent); + float progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, currentTimePercent); if (progress < 0.f || progress > 1.f) { + AreaTriggerCreateProperties const* createProperties = GetCreateProperties(); TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (Id: {}, AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) has wrong progress ({}) caused by curve calculation (MoveCurveId: {})", - GetEntry(), createProperties->Id.Id, uint32(createProperties->Id.IsCustom), progress, createProperties->MoveCurveId); + GetEntry(), createProperties->Id.Id, uint32(createProperties->Id.IsCustom), progress, *m_areaTriggerData->MoveCurveId); } else currentTimePercent = progress; @@ -1317,10 +1400,10 @@ void AreaTrigger::UpdateSplinePosition(Movement::Spline<float>& spline, uint32 d spline.evaluate_percent(lastPositionIndex, percentFromLastPoint, currentPosition); float orientation = _stationaryPosition.GetOrientation(); - if (createProperties && createProperties->FacingCurveId) - orientation += sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress()); + if (m_areaTriggerData->FacingCurveId) + orientation += sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress()); - if (GetCreateProperties() && !GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation) && GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFaceMovementDir)) + if (!HasAreaTriggerFlag(AreaTriggerFieldFlags::AbsoluteOrientation) && HasAreaTriggerFlag(AreaTriggerFieldFlags::FaceMovementDir)) { G3D::Vector3 derivative; spline.evaluate_derivative(lastPositionIndex, percentFromLastPoint, derivative); @@ -1349,14 +1432,11 @@ void AreaTrigger::UpdateOverridePosition() float z = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveZ, progress); float orientation = GetOrientation(); - if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) + if (m_areaTriggerData->FacingCurveId) { - if (createProperties->FacingCurveId) - { - orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress()); - if (!GetCreateProperties() || !GetCreateProperties()->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation)) - orientation += _stationaryPosition.GetOrientation(); - } + orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress()); + if (HasAreaTriggerFlag(AreaTriggerFieldFlags::AbsoluteOrientation)) + orientation += m_areaTriggerData->Facing; } GetMap()->AreaTriggerRelocation(this, x, y, z, orientation); diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h index 67074b04d36..6d10f853063 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.h +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h @@ -39,6 +39,32 @@ namespace Movement class Spline; } +enum class AreaTriggerFieldFlags : uint32 +{ + None = 0x0000, + HeightIgnoresScale = 0x0001, + WowLabsCircle = 0x0002, + CanLoop = 0x0004, + AbsoluteOrientation = 0x0008, + DynamicShape = 0x0010, + Attached = 0x0020, + FaceMovementDir = 0x0040, + FollowsTerrain = 0x0080, + Unknown1025 = 0x0100, + AlwaysExterior = 0x0200, + HasPlayers = 0x0400, +}; + +DEFINE_ENUM_FLAG(AreaTriggerFieldFlags); + +enum class AreaTriggerPathType : int32 +{ + Spline = 0, + Orbit = 1, + None = 2, + MovementScript = 3 +}; + class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<AreaTrigger>, public MapObject { public: @@ -97,9 +123,13 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area bool IsRemoved() const { return _isRemoved; } uint32 GetSpellId() const { return m_areaTriggerData->SpellID; } AuraEffect const* GetAuraEffect() const { return _aurEff; } - uint32 GetTimeSinceCreated() const { return _timeSinceCreated; } + uint32 GetTimeSinceCreated() const; - void SetHeightIgnoresScale(bool heightIgnoresScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::HeightIgnoresScale), heightIgnoresScale); } + EnumFlag<AreaTriggerFieldFlags> GetAreaTriggerFlags() const { return static_cast<AreaTriggerFieldFlags>(*m_areaTriggerData->Flags); } + bool HasAreaTriggerFlag(AreaTriggerFieldFlags flag) const { return GetAreaTriggerFlags().HasFlag(flag); } + void SetAreaTriggerFlag(AreaTriggerFieldFlags flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } + void RemoveAreaTriggerFlag(AreaTriggerFieldFlags flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } + void ReplaceAllAreaTriggerFlags(AreaTriggerFieldFlags flag) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } void SetOverrideScaleCurve(float overrideScale); void SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); @@ -147,19 +177,17 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area uint32 GetFaction() const override; - AreaTriggerShapeInfo const& GetShape() const { return _shape; } + void SetShape(AreaTriggerShapeInfo const& shape); float GetMaxSearchRadius() const; - Position const& GetRollPitchYaw() const { return _rollPitchYaw; } - Position const& GetTargetRollPitchYaw() const { return _targetRollPitchYaw; } void InitSplineOffsets(std::vector<Position> const& offsets, Optional<float> overrideSpeed = {}); void InitSplines(std::vector<G3D::Vector3> const& splinePoints, Optional<float> overrideSpeed = {}); - bool HasSplines() const { return std::holds_alternative<std::unique_ptr<::Movement::Spline<float>>>(_movement); } - ::Movement::Spline<float> const& GetSpline() const { return *std::get<std::unique_ptr<::Movement::Spline<float>>>(_movement); } - uint32 GetElapsedTimeForMovement() const { return GetTimeSinceCreated(); } /// @todo: research the right value, in sniffs both timers are nearly identical + bool HasSplines() const { return _spline != nullptr; } + ::Movement::Spline<float> const& GetSpline() const { return *_spline; } + uint32 GetElapsedTimeForMovement() const; void InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional<float> overrideSpeed = {}); - bool HasOrbit() const { return std::holds_alternative<std::unique_ptr<AreaTriggerOrbitInfo>>(_movement); } - AreaTriggerOrbitInfo const& GetOrbit() const { return *std::get<std::unique_ptr<AreaTriggerOrbitInfo>>(_movement); } + bool HasOrbit() const { return m_areaTriggerData->PathData.Is<UF::AreaTriggerOrbit>(); } + UF::AreaTriggerOrbit const& GetOrbit() const { return *m_areaTriggerData->PathData.Get<UF::AreaTriggerOrbit>(); } bool HasOverridePosition() const; @@ -184,20 +212,20 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area void UpdateTargetList(); void SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D); - void SearchUnitInSphere(std::vector<Unit*>& targetList); - void SearchUnitInBox(std::vector<Unit*>& targetList); - void SearchUnitInPolygon(std::vector<Unit*>& targetList); - void SearchUnitInCylinder(std::vector<Unit*>& targetList); - void SearchUnitInDisk(std::vector<Unit*>& targetList); - void SearchUnitInBoundedPlane(std::vector<Unit*>& targetList); + void SearchUnitInSphere(UF::AreaTriggerSphere const& sphere, std::vector<Unit*>& targetList); + void SearchUnitInBox(UF::AreaTriggerBox const& box, std::vector<Unit*>& targetList); + void SearchUnitInPolygon(UF::AreaTriggerPolygon const& polygon, std::vector<Unit*>& targetList); + void SearchUnitInCylinder(UF::AreaTriggerCylinder const& cylinder, std::vector<Unit*>& targetList); + void SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector<Unit*>& targetList); + void SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector<Unit*>& targetList); void HandleUnitEnterExit(std::vector<Unit*> const& targetList); void DoActions(Unit* unit); void UndoActions(Unit* unit); void UpdatePolygonVertices(); - void UpdateOrbitPosition(AreaTriggerOrbitInfo& orbit, uint32 diff); - void UpdateSplinePosition(Movement::Spline<float>& spline, uint32 diff); + void UpdateOrbitPosition(); + void UpdateSplinePosition(Movement::Spline<float>& spline); void UpdateOverridePosition(); Position const* GetOrbitCenterPosition() const; @@ -212,21 +240,16 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area AuraEffect const* _aurEff; Position _stationaryPosition; - AreaTriggerShapeInfo _shape; int32 _duration; int32 _totalDuration; - uint32 _timeSinceCreated; float _verticesUpdatePreviousOrientation; bool _isRemoved; - Position _rollPitchYaw; - Position _targetRollPitchYaw; std::vector<Position> _polygonVertices; - std::variant<std::monostate, std::unique_ptr<::Movement::Spline<float>>, std::unique_ptr<AreaTriggerOrbitInfo>> _movement; + std::unique_ptr<::Movement::Spline<float>> _spline; bool _reachedDestination; int32 _lastSplineIndex; - uint32 _movementTime; AreaTriggerCreateProperties const* _areaTriggerCreateProperties; AreaTriggerTemplate const* _areaTriggerTemplate; diff --git a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h index 5dba3e6b499..74ce4e2be79 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h +++ b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h @@ -193,9 +193,7 @@ struct AreaTriggerOrbitInfo Optional<TaggedPosition<Position::XYZ>> Center; bool CounterClockwise = false; bool CanLoop = false; - uint32 TimeToTarget = 0; - int32 ElapsedTimeForMovement = 0; - uint32 StartDelay = 0; + int32 ExtraTimeForBlending = 0; float Radius = 0.0f; float BlendFromRadius = 0.0f; float InitialAngle = 0.0f; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 1331c819578..472610d4c0f 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -195,6 +195,7 @@ WorldPacket CreatureTemplate::BuildQueryData(LocaleConstant loc, Difficulty diff stats.Flags[0] = creatureDifficulty->TypeFlags; stats.Flags[1] = creatureDifficulty->TypeFlags2; + stats.Flags[2] = creatureDifficulty->TypeFlags3; stats.CreatureType = type; stats.CreatureFamily = family; @@ -273,6 +274,7 @@ CreatureDifficulty const* CreatureTemplate::GetDifficulty(Difficulty difficulty) CreatureDifficultyID = 0; TypeFlags = 0; TypeFlags2 = 0; + TypeFlags3 = 0; LootID = 0; PickPocketLootID = 0; SkinLootID = 0; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 1f4f4b5e216..81fcb06a14f 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -456,6 +456,7 @@ struct CreatureDifficulty int32 CreatureDifficultyID; uint32 TypeFlags; uint32 TypeFlags2; + uint32 TypeFlags3; uint32 LootID; uint32 PickPocketLootID; uint32 SkinLootID; diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 16f4896d968..1938d8d36d4 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -707,7 +707,7 @@ struct GameObjectTemplate uint32 radius; // 4 radius, int, Min value: 0, Max value: 50, Default value: 10 uint32 InteractRadiusOverride; // 5 Interact Radius Override (Yards * 100), int, Min value: 0, Max value: 2147483647, Default value: 0 uint32 ItemInteractionID; // 6 Item Interaction ID, References: UiItemInteraction, NoValue = 0 - uint32 PlayerInteractionType; // 7 Player Interaction Type, enum { None, TradePartner, Item, Gossip, QuestGiver, Merchant, TaxiNode, Trainer, Banker, AlliedRaceDetailsGiver, GuildBanker, Registrar, Vendor, PetitionVendor, GuildTabardVendor, TalentMaster, SpecializationMaster, MailInfo, SpiritHealer, AreaSpiritHealer, Binder, Auctioneer, StableMaster, BattleMaster, Transmogrifier, LFGDungeon, VoidStorageBanker, BlackMarketAuctioneer, AdventureMap, WorldMap, GarrArchitect, GarrTradeskill, GarrMission, ShipmentCrafter, GarrRecruitment, GarrTalent, Trophy, PlayerChoice, ArtifactForge, ObliterumForge, ScrappingMachine, ContributionCollector, AzeriteRespec, IslandQueue, ItemInteraction, ChromieTime, CovenantPreview, AnimaDiversion, LegendaryCrafting, WeeklyRewards, Soulbind, CovenantSanctum, NewPlayerGuide, ItemUpgrade, AdventureJournal, Renown, AzeriteForge, PerksProgramVendor, ProfessionsCraftingOrder, Professions, ProfessionsCustomerOrder, TraitSystem, BarbersChoice, JailersTowerBuffs, MajorFactionRenown, PersonalTabardVendor, ForgeMaster, CharacterBanker, AccountBanker, ProfessionRespec, PlaceholderType71, PlaceholderType72, PlaceholderType73, PlaceholderType74, PlaceholderType75, PlaceholderType76, PlaceholderType77, }; Default: None + uint32 PlayerInteractionType; // 7 Player Interaction Type, enum { None, TradePartner, Item, Gossip, QuestGiver, Merchant, TaxiNode, Trainer, Banker, AlliedRaceDetailsGiver, GuildBanker, Registrar, Vendor, PetitionVendor, GuildTabardVendor, TalentMaster, SpecializationMaster, MailInfo, SpiritHealer, AreaSpiritHealer, Binder, Auctioneer, StableMaster, BattleMaster, Transmogrifier, LFGDungeon, VoidStorageBanker, BlackMarketAuctioneer, AdventureMap, WorldMap, GarrArchitect, GarrTradeskill, GarrMission, ShipmentCrafter, GarrRecruitment, GarrTalent, Trophy, PlayerChoice, ArtifactForge, ObliterumForge, ScrappingMachine, ContributionCollector, AzeriteRespec, IslandQueue, ItemInteraction, ChromieTime, CovenantPreview, AnimaDiversion, LegendaryCrafting, WeeklyRewards, Soulbind, CovenantSanctum, NewPlayerGuide, ItemUpgrade, AdventureJournal, Renown, AzeriteForge, PerksProgramVendor, ProfessionsCraftingOrder, Professions, ProfessionsCustomerOrder, TraitSystem, BarbersChoice, JailersTowerBuffs, MajorFactionRenown, PersonalTabardVendor, ForgeMaster, CharacterBanker, AccountBanker, ProfessionRespec, PlaceholderType71, PlaceholderType72, PlaceholderType73, PlaceholderType74, PlaceholderType75, PlaceholderType76, GuildRename, PlaceholderType76, }; Default: None } UILink; // 49 GAMEOBJECT_TYPE_KEYSTONE_RECEPTACLE struct @@ -838,6 +838,19 @@ struct GameObjectTemplate uint32 Script; // 0 Script, References: SpellScript, NoValue = 0 uint32 autoClose; // 1 autoClose (ms), int, Min value: 0, Max value: 2147483647, Default value: 3000 } PerksProgramChest; + // 63 GAMEOBJECT_TYPE_FUTURE_PATCH + struct + { + } futurePatchGameObject; + // 64 GAMEOBJECT_TYPE_ASSIST_ACTION + struct + { + uint32 AssistActionType; // 0 Assist Action Type, enum { None, Lounging Player, Grave Marker, Placed VO, Player Guardian, Player Slayer, Captured Buff, }; Default: None + uint32 cooldown; // 1 cooldown, int, Min value: 0, Max value: 2147483647, Default value: 3000 + uint32 gossipID; // 2 gossipID, References: Gossip, NoValue = 0 + uint32 spell; // 3 spell, References: Spell, NoValue = 0 + uint32 playerCast; // 4 playerCast, enum { false, true, }; Default: false + } assistAction; struct { uint32 data[MAX_GAMEOBJECT_DATA]; @@ -1114,6 +1127,8 @@ struct GameObjectTemplate { case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.gossipID; case GAMEOBJECT_TYPE_GOOBER: return goober.gossipID; + case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.gossipID; + case GAMEOBJECT_TYPE_ASSIST_ACTION: return assistAction.gossipID; default: return 0; } } @@ -1216,8 +1231,9 @@ struct GameObjectTemplate { switch (type) { - case GAMEOBJECT_TYPE_TRAP: return trap.cooldown; - case GAMEOBJECT_TYPE_GOOBER: return goober.cooldown; + case GAMEOBJECT_TYPE_TRAP: return trap.cooldown; + case GAMEOBJECT_TYPE_GOOBER: return goober.cooldown; + case GAMEOBJECT_TYPE_ASSIST_ACTION: return assistAction.cooldown; default: return 0; } } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 247517163df..a3b1187cbff 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -141,9 +141,6 @@ void AddItemsSetItem(Player* player, Item const* item) if (itemSetSpell->Threshold > eff->EquippedItems.size()) continue; - if (eff->SetBonuses.count(itemSetSpell)) - continue; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE); if (!spellInfo) { @@ -151,10 +148,17 @@ void AddItemsSetItem(Player* player, Item const* item) continue; } - eff->SetBonuses.insert(itemSetSpell); + if (!eff->SetBonuses.insert(itemSetSpell).second) + continue; + // spell cast only if fit form requirement, in other case will cast at form change - if (!itemSetSpell->ChrSpecID || ChrSpecialization(itemSetSpell->ChrSpecID) == player->GetPrimarySpecialization()) - player->ApplyEquipSpell(spellInfo, nullptr, true); + if (itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != player->GetPrimarySpecialization()) + continue; + + if (itemSetSpell->TraitSubTreeID && int32(itemSetSpell->TraitSubTreeID) != player->m_playerData->CurrentCombatTraitConfigSubTreeID) + continue; + + player->ApplyEquipSpell(spellInfo, nullptr, true); } } } @@ -196,11 +200,10 @@ void RemoveItemsSetItem(Player* player, Item const* item) if (itemSetSpell->Threshold <= eff->EquippedItems.size()) continue; - if (!eff->SetBonuses.count(itemSetSpell)) + if (!eff->SetBonuses.erase(itemSetSpell)) continue; player->ApplyEquipSpell(sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE), nullptr, false); - eff->SetBonuses.erase(itemSetSpell); } } @@ -224,7 +227,8 @@ void UpdateItemSetAuras(Player* player, bool formChange) { SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE); - if (itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != player->GetPrimarySpecialization()) + if ((itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != player->GetPrimarySpecialization()) + || (itemSetSpell->TraitSubTreeID && int32(itemSetSpell->TraitSubTreeID) != player->m_playerData->CurrentCombatTraitConfigSubTreeID)) player->ApplyEquipSpell(spellInfo, nullptr, false, false); // item set aura is not for current spec else { diff --git a/src/server/game/Entities/Item/ItemDefines.h b/src/server/game/Entities/Item/ItemDefines.h index d3278c4987f..0df2bb3bba6 100644 --- a/src/server/game/Entities/Item/ItemDefines.h +++ b/src/server/game/Entities/Item/ItemDefines.h @@ -154,6 +154,8 @@ enum InventoryResult : uint8 EQUIP_ERR_BANK_NOT_ACCESSIBLE = 128,// This character does not have access to this bank. EQUIP_ERR_CANT_TRADE_ACCOUNT_ITEM = 129,// You can't trade an item from the Warband bank. EQUIP_ERR_ACCOUNT_MONEY_LOCKED = 130,// You cannot withdraw or deposit gold from the warband bank currently; please try again later. + EQUIP_ERR_CHARACTER_BANK_NOT_ACCESSIBLE = 131,// This character does not have access to this bank. + EQUIP_ERR_CHARACTER_BANK_NOT_CONVERTED = 132,// Your character's bank has not been converted. Please try again later. }; // EnumUtils: DESCRIBE THIS diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 42b23f04005..c7d97e22fd0 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -811,6 +811,9 @@ enum ItemIdConstants ITEM_PURPLE_RIBBONED_HOLIDAY_GIFT = 17308, // Purple Ribboned Holiday Gift ITEM_EMPTY_WRAPPER = 21830, // Empty Wrapper ITEM_WRAPPED_GIFT = 21831, // Wrappered Gift + + ITEM_ACCOUNT_BANK_TAB_BAG = 208392, // Account Bank Tab Bag (DNT) + ITEM_CHARACTER_BANK_TAB_BAG = 242709, // Character Bank Tab Bag (DNT) }; class Player; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index eaea679d01a..d5b732a145e 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -16,8 +16,6 @@ */ #include "Object.h" -#include "AreaTriggerPackets.h" -#include "AreaTriggerTemplate.h" #include "BattlefieldMgr.h" #include "CellImpl.h" #include "CinematicMgr.h" @@ -46,7 +44,6 @@ #include "SpellAuraEffects.h" #include "SpellMgr.h" #include "SpellPackets.h" -#include "StringConvert.h" #include "TemporarySummon.h" #include "Totem.h" #include "Transport.h" @@ -310,6 +307,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe 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); @@ -318,10 +316,8 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe data->WriteBit(flags.Vehicle); data->WriteBit(flags.AnimKit); data->WriteBit(flags.Rotation); - data->WriteBit(flags.AreaTrigger); data->WriteBit(flags.GameObject); data->WriteBit(flags.SmoothPhasing); - data->WriteBit(flags.ThisIsYou); data->WriteBit(flags.SceneObject); data->WriteBit(flags.ActivePlayer); data->WriteBit(flags.Conversation); @@ -329,7 +325,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe if (flags.MovementUpdate) { - Unit const* unit = ToUnit(); + 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(); @@ -470,14 +466,17 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe } if (flags.CombatVictim) - *data << ToUnit()->GetVictim()->GetGUID(); // 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 = ToUnit(); + Unit const* unit = static_cast<Unit const*>(this); *data << uint32(unit->GetVehicleKit()->GetVehicleInfo()->ID); // RecID *data << float(unit->GetOrientation()); // InitialRawFacing } @@ -491,7 +490,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe } if (flags.Rotation) - *data << uint64(ToGameObject()->GetPackedLocalRotation()); // Rotation + { + GameObject const* gameObject = static_cast<GameObject const*>(this); + *data << uint64(gameObject->GetPackedLocalRotation()); // Rotation + } if (PauseTimes && !PauseTimes->empty()) data->append(PauseTimes->data(), PauseTimes->size()); @@ -502,144 +504,9 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe *data << self->m_movementInfo.transport; } - if (flags.AreaTrigger) - { - AreaTrigger const* areaTrigger = static_cast<AreaTrigger const*>(this); - AreaTriggerCreateProperties const* createProperties = areaTrigger->GetCreateProperties(); - AreaTriggerShapeInfo const& shape = areaTrigger->GetShape(); - - *data << uint32(areaTrigger->GetTimeSinceCreated()); - - *data << areaTrigger->GetRollPitchYaw().PositionXYZStream(); - - switch (shape.Type) - { - case AreaTriggerShapeType::Sphere: - *data << int8(0); - *data << float(shape.SphereDatas.Radius); - *data << float(shape.SphereDatas.RadiusTarget); - break; - case AreaTriggerShapeType::Box: - *data << int8(1); - *data << float(shape.BoxDatas.Extents[0]); - *data << float(shape.BoxDatas.Extents[1]); - *data << float(shape.BoxDatas.Extents[2]); - *data << float(shape.BoxDatas.ExtentsTarget[0]); - *data << float(shape.BoxDatas.ExtentsTarget[1]); - *data << float(shape.BoxDatas.ExtentsTarget[2]); - break; - case AreaTriggerShapeType::Polygon: - *data << int8(3); - *data << int32(shape.PolygonVertices.size()); - *data << int32(shape.PolygonVerticesTarget.size()); - *data << float(shape.PolygonDatas.Height); - *data << float(shape.PolygonDatas.HeightTarget); - - for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVertices) - *data << vertice; - - for (TaggedPosition<Position::XY> const& vertice : shape.PolygonVerticesTarget) - *data << vertice; - break; - case AreaTriggerShapeType::Cylinder: - *data << int8(4); - *data << float(shape.CylinderDatas.Radius); - *data << float(shape.CylinderDatas.RadiusTarget); - *data << float(shape.CylinderDatas.Height); - *data << float(shape.CylinderDatas.HeightTarget); - *data << float(shape.CylinderDatas.LocationZOffset); - *data << float(shape.CylinderDatas.LocationZOffsetTarget); - break; - case AreaTriggerShapeType::Disk: - *data << int8(7); - *data << float(shape.DiskDatas.InnerRadius); - *data << float(shape.DiskDatas.InnerRadiusTarget); - *data << float(shape.DiskDatas.OuterRadius); - *data << float(shape.DiskDatas.OuterRadiusTarget); - *data << float(shape.DiskDatas.Height); - *data << float(shape.DiskDatas.HeightTarget); - *data << float(shape.DiskDatas.LocationZOffset); - *data << float(shape.DiskDatas.LocationZOffsetTarget); - break; - case AreaTriggerShapeType::BoundedPlane: - *data << int8(8); - *data << float(shape.BoundedPlaneDatas.Extents[0]); - *data << float(shape.BoundedPlaneDatas.Extents[1]); - *data << float(shape.BoundedPlaneDatas.ExtentsTarget[0]); - *data << float(shape.BoundedPlaneDatas.ExtentsTarget[1]); - break; - default: - break; - } - - bool hasAbsoluteOrientation = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAbsoluteOrientation); - bool hasDynamicShape = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasDynamicShape); - bool hasAttached = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasAttached); - bool hasFaceMovementDir = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFaceMovementDir); - bool hasFollowsTerrain = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasFollowsTerrain); - bool hasAlwaysExterior = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::AlwaysExterior); - bool hasUnknown1025 = false; - bool hasTargetRollPitchYaw = createProperties && createProperties->Flags.HasFlag(AreaTriggerCreatePropertiesFlag::HasTargetRollPitchYaw); - bool hasScaleCurveID = createProperties && createProperties->ScaleCurveId != 0; - bool hasMorphCurveID = createProperties && createProperties->MorphCurveId != 0; - bool hasFacingCurveID = createProperties && createProperties->FacingCurveId != 0; - bool hasMoveCurveID = createProperties && createProperties->MoveCurveId != 0; - bool hasMovementScript = false; - bool hasPositionalSoundKitID= false; - - data->WriteBit(hasAbsoluteOrientation); - data->WriteBit(hasDynamicShape); - data->WriteBit(hasAttached); - data->WriteBit(hasFaceMovementDir); - data->WriteBit(hasFollowsTerrain); - data->WriteBit(hasAlwaysExterior); - data->WriteBit(hasUnknown1025); - data->WriteBit(hasTargetRollPitchYaw); - data->WriteBit(hasScaleCurveID); - data->WriteBit(hasMorphCurveID); - data->WriteBit(hasFacingCurveID); - data->WriteBit(hasMoveCurveID); - data->WriteBit(hasPositionalSoundKitID); - data->WriteBit(areaTrigger->HasSplines()); - data->WriteBit(areaTrigger->HasOrbit()); - data->WriteBit(hasMovementScript); - - data->FlushBits(); - - if (areaTrigger->HasSplines()) - WorldPackets::AreaTrigger::WriteAreaTriggerSpline(*data, areaTrigger->GetTimeToTarget(), areaTrigger->GetElapsedTimeForMovement(), areaTrigger->GetSpline()); - - if (hasTargetRollPitchYaw) - *data << areaTrigger->GetTargetRollPitchYaw().PositionXYZStream(); - - if (hasScaleCurveID) - *data << uint32(createProperties->ScaleCurveId); - - if (hasMorphCurveID) - *data << uint32(createProperties->MorphCurveId); - - if (hasFacingCurveID) - *data << uint32(createProperties->FacingCurveId); - - if (hasMoveCurveID) - *data << uint32(createProperties->MoveCurveId); - - if (hasPositionalSoundKitID) - *data << uint32(0); - - //if (hasMovementScript) - // *data << *areaTrigger->GetMovementScript(); // AreaTriggerMovementScriptInfo - - if (areaTrigger->HasOrbit()) - { - using WorldPackets::AreaTrigger::operator<<; - *data << areaTrigger->GetOrbit(); - } - } - if (flags.GameObject) { - GameObject const* gameObject = ToGameObject(); + GameObject const* gameObject = static_cast<GameObject const*>(this); Transport const* transport = gameObject->ToTransport(); bool bit8 = false; @@ -794,10 +661,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe if (flags.ActivePlayer) { - Player const* player = ToPlayer(); + Player const* player = static_cast<Player const*>(this); bool HasSceneInstanceIDs = !player->GetSceneMgr().GetSceneTemplateByInstanceMap().empty(); - bool HasRuneState = ToUnit()->GetPowerIndex(POWER_RUNES) != MAX_POWERS; + bool HasRuneState = player->GetPowerIndex(POWER_RUNES) != MAX_POWERS; data->WriteBit(HasSceneInstanceIDs); data->WriteBit(HasRuneState); @@ -805,8 +672,8 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe if (HasSceneInstanceIDs) { *data << uint32(player->GetSceneMgr().GetSceneTemplateByInstanceMap().size()); - for (auto const& itr : player->GetSceneMgr().GetSceneTemplateByInstanceMap()) - *data << uint32(itr.first); + for (auto const& [sceneInstanceId, _] : player->GetSceneMgr().GetSceneTemplateByInstanceMap()) + *data << uint32(sceneInstanceId); } if (HasRuneState) { @@ -823,7 +690,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe if (flags.Conversation) { - Conversation const* self = ToConversation(); + Conversation const* self = static_cast<Conversation const*>(this); if (data->WriteBit(self->GetTextureKitId() != 0)) *data << uint32(self->GetTextureKitId()); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index b5940dc0b73..971b74494e0 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -93,7 +93,6 @@ struct CreateObjectBits bool Vehicle : 1; bool AnimKit : 1; bool Rotation : 1; - bool AreaTrigger : 1; bool GameObject : 1; bool SmoothPhasing : 1; bool ThisIsYou : 1; diff --git a/src/server/game/Entities/Object/Updates/UpdateField.h b/src/server/game/Entities/Object/Updates/UpdateField.h index ef802f8447d..874b38d87d8 100644 --- a/src/server/game/Entities/Object/Updates/UpdateField.h +++ b/src/server/game/Entities/Object/Updates/UpdateField.h @@ -23,6 +23,7 @@ #include "UpdateMask.h" #include <algorithm> #include <memory> +#include <variant> #include <vector> class ByteBuffer; @@ -68,6 +69,15 @@ namespace UF template<typename T, int32 BlockBit, uint32 Bit> class OptionalUpdateField; + template<typename T> + inline constexpr std::type_identity<T> VariantCase; + + template<typename... Types> + class VariantUpdateFieldBase; + + template<int32 BlockBit, uint32 Bit, typename... Types> + class VariantUpdateField; + template<typename T, bool PublicSet> struct MutableFieldReferenceWithChangesMask; @@ -352,6 +362,24 @@ namespace UF return { *((_value.*field)._value) }; } + template<typename V, int32 BlockBit, uint32 Bit, typename... Types> + std::conditional_t<std::is_base_of_v<IsUpdateFieldStructureTag, V>, + MutableFieldReference<V, PublicSet>, + std::conditional_t<std::is_base_of_v<IsUpdateFieldHolderTag, V>, + MutableNestedFieldReference<V, PublicSet>, + UpdateFieldSetter<V, PublicSet>>> + ModifyValue(VariantUpdateField<BlockBit, Bit, Types...>(T::* field), [[maybe_unused]] std::type_identity<V> type) + { + if (!(_value.*field).template Is<V>()) + (_value.*field).template ConstructValue<V>(); + + if constexpr (BlockBit >= 0) + _value._changesMask.Set(BlockBit); + + _value._changesMask.Set(Bit); + return { *((_value.*field).template Get<V>()) }; + } + private: T& _value; }; @@ -538,6 +566,17 @@ namespace UF _changesMask.Set(Bit); } + template<typename Derived, int32 BlockBit, uint32 Bit, typename... Types> + void MarkChanged(VariantUpdateField<BlockBit, Bit, Types...>(Derived::*)) + { + static_assert(std::is_base_of_v<Base, Derived>, "Given field argument must belong to the same structure as this HasChangesMask"); + + if constexpr (BlockBit >= 0) + _changesMask.Set(BlockBit); + + _changesMask.Set(Bit); + } + template<typename Derived, typename T, int32 BlockBit, uint32 Bit> void ClearChanged(UpdateField<T, BlockBit, Bit>(Derived::*)) { @@ -578,6 +617,14 @@ namespace UF _changesMask.Reset(Bit); } + template<typename Derived, int32 BlockBit, uint32 Bit, typename... Types> + void ClearChanged(VariantUpdateField<BlockBit, Bit, Types...>(Derived::*)) + { + static_assert(std::is_base_of_v<Base, Derived>, "Given field argument must belong to the same structure as this HasChangesMask"); + + _changesMask.Reset(Bit); + } + Mask const& GetChangesMask() const { return _changesMask; } protected: @@ -614,6 +661,17 @@ namespace UF field._value->ClearChangesMask(); } + template<int32 BlockBit, uint32 Bit, typename... Types> + static void ClearChangesMask(VariantUpdateField<BlockBit, Bit, Types...>& field) + { + if constexpr ((std::is_base_of_v<HasChangesMaskTag, Types> || ...)) + std::visit([]<typename T>(T& value) + { + if constexpr (std::is_base_of_v<HasChangesMaskTag, T>) + value.ClearChangesMask(); + }, field._value); + } + Mask _changesMask; }; @@ -894,6 +952,64 @@ namespace UF { }; + template<typename... Types> + class VariantUpdateFieldBase : public IsUpdateFieldHolderTag + { + template<typename F, bool PublicSet> + friend struct MutableFieldReferenceWithChangesMask; + + template<typename F, bool PublicSet> + friend struct MutableFieldReferenceNoChangesMask; + + template<typename F, bool PublicSet> + friend struct MutableNestedFieldReference; + + template<std::size_t Bits> + friend class HasChangesMask; + + friend class UpdateFieldHolder; + + public: + template<typename T> + bool Is() const { return std::holds_alternative<T>(_value); } + + template<typename T> + T const* Get() const noexcept + { + if (std::holds_alternative<T>(_value)) + return &std::get<T>(_value); + return nullptr; + } + + template<typename Visitor> + decltype(auto) Visit(Visitor&& visitor) const noexcept + { + return std::visit(std::forward<Visitor>(visitor), _value); + } + + private: + template<typename T> + void ConstructValue() + { + _value.template emplace<T>(); + } + + template<typename T> + T* Get() noexcept + { + if (std::holds_alternative<T>(_value)) + return &std::get<T>(_value); + return nullptr; + } + + std::variant<std::monostate, Types...> _value; + }; + + template<int32 BlockBit, uint32 Bit, typename... Types> + class VariantUpdateField : public VariantUpdateFieldBase<Types...> + { + }; + template<typename T> struct ViewerDependentValueTag { diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index a86aa7f9988..f70dc26de37 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -20,6 +20,7 @@ #include "ByteBuffer.h" #include "Corpse.h" #include "DynamicObject.h" +#include "PacketOperators.h" #include "Player.h" #include "ViewerDependentValues.h" @@ -852,18 +853,24 @@ void UnitChannel::WriteCreate(ByteBuffer& data, Unit const* owner, Player const* { data << int32(SpellID); SpellVisual.WriteCreate(data, owner, receiver); + data << uint32(StartTimeMs); + data << uint32(Duration); } void UnitChannel::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Unit const* owner, Player const* receiver) const { data << int32(SpellID); SpellVisual.WriteUpdate(data, ignoreChangesMask, owner, receiver); + data << uint32(StartTimeMs); + data << uint32(Duration); } bool UnitChannel::operator==(UnitChannel const& right) const { return SpellID == right.SpellID - && SpellVisual == right.SpellVisual; + && SpellVisual == right.SpellVisual + && StartTimeMs == right.StartTimeMs + && Duration == right.Duration; } void VisibleItem::WriteCreate(ByteBuffer& data, Unit const* owner, Player const* receiver) const @@ -937,6 +944,51 @@ bool PassiveSpellHistory::operator==(PassiveSpellHistory const& right) const && AuraSpellID == right.AuraSpellID; } +void UnitAssistActionData::WriteCreate(ByteBuffer& data, Unit const* owner, Player const* receiver) const +{ + data << uint8(Type); + data << uint32(VirtualRealmAddress); + data.WriteBits(PlayerName->size(), 6); + data.FlushBits(); + data << WorldPackets::SizedString::Data(*PlayerName); +} + +void UnitAssistActionData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Unit const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 4); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << uint8(Type); + } + if (changesMask[3]) + { + data << uint32(VirtualRealmAddress); + } + if (changesMask[2]) + { + data.WriteBits(PlayerName->size(), 6); + data.FlushBits(); + data << WorldPackets::SizedString::Data(*PlayerName); + } + } +} + +void UnitAssistActionData::ClearChangesMask() +{ + Base::ClearChangesMask(Type); + Base::ClearChangesMask(PlayerName); + Base::ClearChangesMask(VirtualRealmAddress); + _changesMask.ResetAll(); +} + void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const { ViewerDependentValue<StateWorldEffectIDsTag>::value_type stateWorldEffectIDs = {}; @@ -1148,18 +1200,24 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi { data << ChannelObjects[i]; } + data.FlushBits(); data.WriteBit(Field_314); + data.WriteBits(AssistActionData.has_value(), 1); + if (AssistActionData.has_value()) + { + AssistActionData->WriteCreate(data, owner, receiver); + } data.FlushBits(); } static constexpr void UnitDataAppendAllowedFieldsMaskForFlag(UnitData::Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) - allowedMaskForTarget |= std::array<uint32, 7>{ 0x00010000u, 0xF0040000u, 0xFF080000u, 0x000007FEu, 0xF0000080u, 0xFF80FFFFu, 0x3FFFFFFFu }; + allowedMaskForTarget |= std::array<uint32, 7>{ 0x00010000u, 0xF0040000u, 0xFF080000u, 0x000007FEu, 0xE0000100u, 0xFF01FFFFu, 0x7FFFFFFFu }; if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::UnitAll)) - allowedMaskForTarget |= std::array<uint32, 7>{ 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xF0000080u, 0x0000FFFFu, 0x00000000u }; + allowedMaskForTarget |= std::array<uint32, 7>{ 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xE0000100u, 0x0001FFFFu, 0x00000000u }; if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Empath)) - allowedMaskForTarget |= std::array<uint32, 7>{ 0x00000000u, 0xF0000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x0000FF00u }; + allowedMaskForTarget |= std::array<uint32, 7>{ 0x00000000u, 0xF0000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x0001FE00u }; } void UnitData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) @@ -1169,14 +1227,14 @@ void UnitData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFl void UnitData::FilterDisallowedFieldsMaskForFlag(Mask& changesMask, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { - Mask allowedMaskForTarget({ 0xFFFEFFFFu, 0x0FFBFFFFu, 0x00F7FFFFu, 0xFFFFF801u, 0x0FFFFFFFu, 0x007F0000u, 0x00000000u }); + Mask allowedMaskForTarget({ 0xFFFEFFFFu, 0x0FFBFFFFu, 0x00F7FFFFu, 0xFFFFF801u, 0x1FFFFFFFu, 0x00FE0000u, 0x00000000u }); UnitDataAppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); changesMask &= allowedMaskForTarget; } void UnitData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const { - Mask allowedMaskForTarget({ 0xFFFEFFFFu, 0x0FFBFFFFu, 0x00F7FFFFu, 0xFFFFF801u, 0x0FFFFFFFu, 0x007F0000u, 0x00000000u }); + Mask allowedMaskForTarget({ 0xFFFEFFFFu, 0x0FFBFFFFu, 0x00F7FFFFu, 0xFFFFF801u, 0x1FFFFFFFu, 0x00FE0000u, 0x00000000u }); UnitDataAppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); WriteUpdate(data, _changesMask & allowedMaskForTarget, false, owner, receiver); } @@ -1776,84 +1834,93 @@ void UnitData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor { data << *NameplateAttachToGUID; } + data.WriteBits(AssistActionData.has_value(), 1); + data.FlushBits(); + if (changesMask[135]) + { + if (AssistActionData.has_value()) + { + AssistActionData->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } } - if (changesMask[135]) + if (changesMask[136]) { for (uint32 i = 0; i < 10; ++i) { - if (changesMask[136 + i]) + if (changesMask[137 + i]) { data << int32(Power[i]); } - if (changesMask[146 + i]) + if (changesMask[147 + i]) { data << int32(MaxPower[i]); } - if (changesMask[156 + i]) + if (changesMask[157 + i]) { data << float(PowerRegenFlatModifier[i]); } - if (changesMask[166 + i]) + if (changesMask[167 + i]) { data << float(PowerRegenInterruptedFlatModifier[i]); } } } - if (changesMask[176]) + if (changesMask[177]) { for (uint32 i = 0; i < 3; ++i) { - if (changesMask[177 + i]) + if (changesMask[178 + i]) { VirtualItems[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[180]) + if (changesMask[181]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[181 + i]) + if (changesMask[182 + i]) { data << uint32(AttackRoundBaseTime[i]); } } } - if (changesMask[183]) + if (changesMask[184]) { for (uint32 i = 0; i < 4; ++i) { - if (changesMask[184 + i]) + if (changesMask[185 + i]) { data << int32(Stats[i]); } - if (changesMask[188 + i]) + if (changesMask[189 + i]) { data << int32(StatPosBuff[i]); } - if (changesMask[192 + i]) + if (changesMask[193 + i]) { data << int32(StatNegBuff[i]); } - if (changesMask[196 + i]) + if (changesMask[197 + i]) { data << int32(StatSupportBuff[i]); } } } - if (changesMask[200]) + if (changesMask[201]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[201 + i]) + if (changesMask[202 + i]) { data << int32(Resistances[i]); } - if (changesMask[208 + i]) + if (changesMask[209 + i]) { data << int32(BonusResistanceMods[i]); } - if (changesMask[215 + i]) + if (changesMask[216 + i]) { data << int32(ManaCostModifier[i]); } @@ -1994,6 +2061,7 @@ void UnitData::ClearChangesMask() Base::ClearChangesMask(Field_31C); Base::ClearChangesMask(Field_320); Base::ClearChangesMask(NameplateAttachToGUID); + Base::ClearChangesMask(AssistActionData); Base::ClearChangesMask(Power); Base::ClearChangesMask(MaxPower); Base::ClearChangesMask(PowerRegenFlatModifier); @@ -2196,7 +2264,7 @@ void PetCreatureName::WriteCreate(ByteBuffer& data, Player const* owner, Player { data << uint32(CreatureID); data.WriteBits(Name->size(), 8); - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); data.FlushBits(); } @@ -2218,7 +2286,7 @@ void PetCreatureName::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Play if (changesMask[2]) { data.WriteBits(Name->size(), 8); - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); } } data.FlushBits(); @@ -2252,6 +2320,50 @@ bool CTROptions::operator==(CTROptions const& right) const && ChromieTimeExpansionMask == right.ChromieTimeExpansionMask; } +void LeaverInfo::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << BnetAccountGUID; + data << float(LeaveScore); + data << uint32(SeasonID); + data << uint32(TotalLeaves); + data << uint32(TotalSuccesses); + data << int32(ConsecutiveSuccesses); + data << int64(LastPenaltyTime); + data << int64(LeaverExpirationTime); + data << int32(Unknown_1120); + data.WriteBits(LeaverStatus, 1); + data.FlushBits(); +} + +void LeaverInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + data << BnetAccountGUID; + data << float(LeaveScore); + data << uint32(SeasonID); + data << uint32(TotalLeaves); + data << uint32(TotalSuccesses); + data << int32(ConsecutiveSuccesses); + data << int64(LastPenaltyTime); + data << int64(LeaverExpirationTime); + data << int32(Unknown_1120); + data.WriteBits(LeaverStatus, 1); + data.FlushBits(); +} + +bool LeaverInfo::operator==(LeaverInfo const& right) const +{ + return BnetAccountGUID == right.BnetAccountGUID + && LeaveScore == right.LeaveScore + && SeasonID == right.SeasonID + && TotalLeaves == right.TotalLeaves + && TotalSuccesses == right.TotalSuccesses + && ConsecutiveSuccesses == right.ConsecutiveSuccesses + && LastPenaltyTime == right.LastPenaltyTime + && LeaverExpirationTime == right.LeaverExpirationTime + && Unknown_1120 == right.Unknown_1120 + && LeaverStatus == right.LeaverStatus; +} + void DeclinedNames::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const { for (uint32 i = 0; i < 5; ++i) @@ -2260,7 +2372,7 @@ void DeclinedNames::WriteCreate(ByteBuffer& data, Player const* owner, Player co } for (uint32 i = 0; i < 5; ++i) { - data.WriteString(Name[i]); + data << WorldPackets::SizedString::Data(Name[i]); } data.FlushBits(); } @@ -2292,7 +2404,7 @@ void DeclinedNames::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player { if (changesMask[1 + i]) { - data.WriteString(Name[i]); + data << WorldPackets::SizedString::Data(Name[i]); } } } @@ -2398,6 +2510,7 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi data << int32(FakeInebriation); data << uint32(VirtualPlayerRealm); data << uint32(CurrentSpecID); + data << int32(CurrentCombatTraitConfigSubTreeID); data << int32(TaxiMountAnimKitID); for (uint32 i = 0; i < 6; ++i) { @@ -2458,7 +2571,8 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi data.WriteBit(HasLevelLink); data.WriteBits(DeclinedNames.has_value(), 1); data << *DungeonScore; - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); + LeaverInfo->WriteCreate(data, owner, receiver); for (uint32 i = 0; i < 16; ++i) { data << VisibleEquipableSpells[i]; @@ -2477,7 +2591,7 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi static constexpr void PlayerDataAppendAllowedFieldsMaskForFlag(PlayerData::Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::PartyMember)) - allowedMaskForTarget |= std::array<uint32, 11>{ 0x00000022u, 0xFFFE0000u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u }; + allowedMaskForTarget |= std::array<uint32, 11>{ 0x00000022u, 0xFFF80000u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000007u, 0x00000000u, 0x00000000u, 0x00000000u }; } void PlayerData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) @@ -2487,14 +2601,14 @@ void PlayerData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, Enum void PlayerData::FilterDisallowedFieldsMaskForFlag(Mask& changesMask, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { - Mask allowedMaskForTarget({ 0xFFFFFFDDu, 0x0001FFFFu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xFFFFFFFEu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000003u }); + Mask allowedMaskForTarget({ 0xFFFFFFDDu, 0x0007FFFFu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xFFFFFFF8u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000000Fu }); PlayerDataAppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); changesMask &= allowedMaskForTarget; } void PlayerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const { - Mask allowedMaskForTarget({ 0xFFFFFFDDu, 0x0001FFFFu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xFFFFFFFEu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000003u }); + Mask allowedMaskForTarget({ 0xFFFFFFDDu, 0x0007FFFFu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xFFFFFFF8u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0000000Fu }); PlayerDataAppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); WriteUpdate(data, _changesMask & allowedMaskForTarget, false, owner, receiver); } @@ -2708,74 +2822,82 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign } if (changesMask[29]) { - data << int32(TaxiMountAnimKitID); + data << int32(CurrentCombatTraitConfigSubTreeID); } if (changesMask[30]) { - data << uint8(CurrentBattlePetBreedQuality); + data << int32(TaxiMountAnimKitID); } if (changesMask[31]) { - data << int32(HonorLevel); + data << uint8(CurrentBattlePetBreedQuality); } } if (changesMask[32]) { if (changesMask[33]) { + data << int32(HonorLevel); + } + if (changesMask[34]) + { data << int64(LogoutTime); } - if (changesMask[35]) + if (changesMask[36]) { data << int32(Field_1AC); } - if (changesMask[36]) + if (changesMask[37]) { data << int32(Field_1B0); } - if (changesMask[37]) + if (changesMask[38]) { data << int32(CurrentBattlePetSpeciesID); } - if (changesMask[38]) + if (changesMask[39]) { CtrOptions->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[39]) + if (changesMask[40]) { data << int32(CovenantID); } - if (changesMask[40]) + if (changesMask[41]) { data << int32(SoulbindID); } - if (changesMask[42]) + if (changesMask[44]) { data << *SpectateTarget; } - if (changesMask[43]) + if (changesMask[45]) { data << int32(Field_200); } - if (changesMask[45]) + if (changesMask[47]) { PersonalTabard->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[34]) + if (changesMask[35]) { data.WriteBits(Name->size(), 6); } data.WriteBits(DeclinedNames.has_value(), 1); data.FlushBits(); - if (changesMask[41]) + if (changesMask[42]) { data << *DungeonScore; } - if (changesMask[34]) + if (changesMask[35]) { - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); } - if (changesMask[44]) + if (changesMask[43]) + { + LeaverInfo->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (changesMask[46]) { if (DeclinedNames.has_value()) { @@ -2783,21 +2905,21 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign } } } - if (changesMask[46]) + if (changesMask[48]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[47 + i]) + if (changesMask[49 + i]) { data << uint8(PartyType[i]); } } } - if (changesMask[49]) + if (changesMask[51]) { for (uint32 i = 0; i < 175; ++i) { - if (changesMask[50 + i]) + if (changesMask[52 + i]) { if (noQuestLogChangesMask) QuestLog[i].WriteCreate(data, owner, receiver); @@ -2806,51 +2928,51 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign } } } - if (changesMask[225]) + if (changesMask[227]) { for (uint32 i = 0; i < 19; ++i) { - if (changesMask[226 + i]) + if (changesMask[228 + i]) { VisibleItems[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[245]) + if (changesMask[247]) { for (uint32 i = 0; i < 6; ++i) { - if (changesMask[246 + i]) + if (changesMask[248 + i]) { data << float(AvgItemLevel[i]); } } } - if (changesMask[252]) + if (changesMask[254]) { for (uint32 i = 0; i < 32; ++i) { - if (changesMask[253 + i]) + if (changesMask[255 + i]) { ForcedReactions[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[302]) + if (changesMask[304]) { for (uint32 i = 0; i < 19; ++i) { - if (changesMask[303 + i]) + if (changesMask[305 + i]) { data << uint32(Field_3120[i]); } } } - if (changesMask[285]) + if (changesMask[287]) { for (uint32 i = 0; i < 16; ++i) { - if (changesMask[286 + i]) + if (changesMask[288 + i]) { data << VisibleEquipableSpells[i]; } @@ -2889,6 +3011,7 @@ void PlayerData::ClearChangesMask() Base::ClearChangesMask(FakeInebriation); Base::ClearChangesMask(VirtualPlayerRealm); Base::ClearChangesMask(CurrentSpecID); + Base::ClearChangesMask(CurrentCombatTraitConfigSubTreeID); Base::ClearChangesMask(TaxiMountAnimKitID); Base::ClearChangesMask(CurrentBattlePetBreedQuality); Base::ClearChangesMask(HonorLevel); @@ -2901,6 +3024,7 @@ void PlayerData::ClearChangesMask() Base::ClearChangesMask(CovenantID); Base::ClearChangesMask(SoulbindID); Base::ClearChangesMask(DungeonScore); + Base::ClearChangesMask(LeaverInfo); Base::ClearChangesMask(SpectateTarget); Base::ClearChangesMask(Field_200); Base::ClearChangesMask(DeclinedNames); @@ -3613,6 +3737,7 @@ void TraitEntry::WriteCreate(ByteBuffer& data, Player const* owner, Player const data << int32(TraitNodeEntryID); data << int32(Rank); data << int32(GrantedRanks); + data << int32(BonusRanks); } void TraitEntry::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const @@ -3621,6 +3746,7 @@ void TraitEntry::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player co data << int32(TraitNodeEntryID); data << int32(Rank); data << int32(GrantedRanks); + data << int32(BonusRanks); } bool TraitEntry::operator==(TraitEntry const& right) const @@ -3628,7 +3754,8 @@ bool TraitEntry::operator==(TraitEntry const& right) const return TraitNodeID == right.TraitNodeID && TraitNodeEntryID == right.TraitNodeEntryID && Rank == right.Rank - && GrantedRanks == right.GrantedRanks; + && GrantedRanks == right.GrantedRanks + && BonusRanks == right.BonusRanks; } void TraitSubTreeCache::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const @@ -3692,7 +3819,7 @@ void TraitConfig::WriteCreate(ByteBuffer& data, Player const* owner, Player cons { SubTrees[i].WriteCreate(data, owner, receiver); } - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); data.FlushBits(); } @@ -3802,7 +3929,7 @@ void TraitConfig::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player c if (changesMask[5]) { data.WriteBits(Name->size(), 9); - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); } } data.FlushBits(); @@ -3987,7 +4114,7 @@ void CraftingOrderData::WriteCreate(ByteBuffer& data, Player const* owner, Playe { Reagents[i].WriteCreate(data, owner, receiver); } - data.WriteString(CustomerNotes); + data << WorldPackets::SizedString::Data(*CustomerNotes); if (Customer.has_value()) { Customer->WriteCreate(data, owner, receiver); @@ -4123,7 +4250,7 @@ void CraftingOrderData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Pl { if (changesMask[20]) { - data.WriteString(CustomerNotes); + data << WorldPackets::SizedString::Data(*CustomerNotes); } if (changesMask[21]) { @@ -4398,7 +4525,7 @@ void StablePetInfo::WriteCreate(ByteBuffer& data, Player const* owner, Player co data << uint8(PetFlags); data << uint32(Specialization); data.WriteBits(Name->size(), 8); - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); data.FlushBits(); } @@ -4444,7 +4571,7 @@ void StablePetInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player if (changesMask[6]) { data.WriteBits(Name->size(), 8); - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); } } data.FlushBits(); @@ -4565,9 +4692,9 @@ void BankTabSettings::WriteCreate(ByteBuffer& data, Player const* owner, Player data.WriteBits(Icon->size(), 9); data.WriteBits(Description->size(), 14); data << int32(DepositFlags); - data.WriteString(Name); - data.WriteString(Icon); - data.WriteString(Description); + data << WorldPackets::SizedString::Data(*Name); + data << WorldPackets::SizedString::Data(*Icon); + data << WorldPackets::SizedString::Data(*Description); data.FlushBits(); } @@ -4598,15 +4725,15 @@ void BankTabSettings::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Play } if (changesMask[0]) { - data.WriteString(Name); + data << WorldPackets::SizedString::Data(*Name); } if (changesMask[1]) { - data.WriteString(Icon); + data << WorldPackets::SizedString::Data(*Icon); } if (changesMask[2]) { - data.WriteString(Description); + data << WorldPackets::SizedString::Data(*Description); } data.FlushBits(); } @@ -4687,6 +4814,47 @@ bool DelveData::operator==(DelveData const& right) const && Started == right.Started; } +void ChallengeModeData::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << int32(Unknown_1120_1); + data << int32(Unknown_1120_2); + data << uint64(Unknown_1120_3); + data << int64(Unknown_1120_4); + data << KeystoneOwnerGUID; + data << LeaverGUID; + data.WriteBits(IsActive, 1); + data.WriteBits(HasRestrictions, 1); + data.WriteBits(CanVoteAbandon, 1); + data.FlushBits(); +} + +void ChallengeModeData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + data << int32(Unknown_1120_1); + data << int32(Unknown_1120_2); + data << uint64(Unknown_1120_3); + data << int64(Unknown_1120_4); + data << KeystoneOwnerGUID; + data << LeaverGUID; + data.WriteBits(IsActive, 1); + data.WriteBits(HasRestrictions, 1); + data.WriteBits(CanVoteAbandon, 1); + data.FlushBits(); +} + +bool ChallengeModeData::operator==(ChallengeModeData const& right) const +{ + return Unknown_1120_1 == right.Unknown_1120_1 + && Unknown_1120_2 == right.Unknown_1120_2 + && Unknown_1120_3 == right.Unknown_1120_3 + && Unknown_1120_4 == right.Unknown_1120_4 + && KeystoneOwnerGUID == right.KeystoneOwnerGUID + && LeaverGUID == right.LeaverGUID + && IsActive == right.IsActive + && HasRestrictions == right.HasRestrictions + && CanVoteAbandon == right.CanVoteAbandon; +} + void Research::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const { data << int16(ResearchProjectID); @@ -4704,7 +4872,7 @@ bool Research::operator==(Research const& right) const void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const { - for (uint32 i = 0; i < 232; ++i) + for (uint32 i = 0; i < 105; ++i) { data << InvSlots[i]; } @@ -4819,14 +4987,11 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f { data << uint32(BagSlotFlags[i]); } - for (uint32 i = 0; i < 7; ++i) - { - data << uint32(BankBagSlotFlags[i]); - } data << int32(Honor); data << int32(HonorNextLevel); data << int32(PerksProgramCurrency); data << uint8(NumBankSlots); + data << uint8(NumCharacterBankTabs); data << uint8(NumAccountBankTabs); for (uint32 i = 0; i < 1; ++i) { @@ -5017,9 +5182,11 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f data.WriteBit(HasPerksProgramPendingReward); data.WriteBits(QuestSession.has_value(), 1); data.WriteBits(PetStable.has_value(), 1); + data.WriteBits(CharacterBankTabSettings.size(), 3); data.WriteBits(AccountBankTabSettings.size(), 3); data.WriteBits(WalkInData.has_value(), 1); data.WriteBits(DelveData.has_value(), 1); + data.WriteBits(ChallengeModeData.has_value(), 1); data.FlushBits(); ResearchHistory->WriteCreate(data, owner, receiver); if (QuestSession.has_value()) @@ -5049,6 +5216,10 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f { PetStable->WriteCreate(data, owner, receiver); } + for (uint32 i = 0; i < CharacterBankTabSettings.size(); ++i) + { + CharacterBankTabSettings[i].WriteCreate(data, owner, receiver); + } for (uint32 i = 0; i < AccountBankTabSettings.size(); ++i) { AccountBankTabSettings[i].WriteCreate(data, owner, receiver); @@ -5061,6 +5232,10 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f { DelveData->WriteCreate(data, owner, receiver); } + if (ChallengeModeData.has_value()) + { + ChallengeModeData->WriteCreate(data, owner, receiver); + } data.FlushBits(); } @@ -5071,8 +5246,8 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, Player const* owner, Player const* receiver) const { - data.WriteBits(changesMask.GetBlocksMask(0), 17); - for (uint32 i = 0; i < 17; ++i) + data.WriteBits(changesMask.GetBlocksMask(0), 13); + for (uint32 i = 0; i < 13; ++i) if (changesMask.GetBlock(i)) data.WriteBits(changesMask.GetBlock(i), 32); @@ -5131,11 +5306,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo WriteCompleteDynamicFieldUpdateMask(PvpInfo.size(), data); } } - if (changesMask[42]) + if (changesMask[43]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[43]) + if (changesMask[44]) { if (!ignoreNestedChangesMask) ResearchSites[i].WriteUpdateMask(data); @@ -5144,11 +5319,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[44]) + if (changesMask[45]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[45]) + if (changesMask[46]) { if (!ignoreNestedChangesMask) ResearchSiteProgress[i].WriteUpdateMask(data); @@ -5157,11 +5332,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[46]) + if (changesMask[47]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[47]) + if (changesMask[48]) { if (!ignoreNestedChangesMask) Research[i].WriteUpdateMask(data); @@ -5170,11 +5345,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[42]) + if (changesMask[43]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[43]) + if (changesMask[44]) { for (uint32 j = 0; j < ResearchSites[i].size(); ++j) { @@ -5186,11 +5361,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[44]) + if (changesMask[45]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[45]) + if (changesMask[46]) { for (uint32 j = 0; j < ResearchSiteProgress[i].size(); ++j) { @@ -5202,11 +5377,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[46]) + if (changesMask[47]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[47]) + if (changesMask[48]) { for (uint32 j = 0; j < Research[i].size(); ++j) { @@ -5731,6 +5906,13 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo if (changesMask[41]) { if (!ignoreNestedChangesMask) + CharacterBankTabSettings.WriteUpdateMask(data, 3); + else + WriteCompleteDynamicFieldUpdateMask(CharacterBankTabSettings.size(), data, 3); + } + if (changesMask[42]) + { + if (!ignoreNestedChangesMask) AccountBankTabSettings.WriteUpdateMask(data, 3); else WriteCompleteDynamicFieldUpdateMask(AccountBankTabSettings.size(), data, 3); @@ -5784,6 +5966,16 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } if (changesMask[41]) { + for (uint32 i = 0; i < CharacterBankTabSettings.size(); ++i) + { + if (CharacterBankTabSettings.HasChanged(i) || ignoreNestedChangesMask) + { + CharacterBankTabSettings[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + } + if (changesMask[42]) + { for (uint32 i = 0; i < AccountBankTabSettings.size(); ++i) { if (AccountBankTabSettings.HasChanged(i) || ignoreNestedChangesMask) @@ -5792,364 +5984,368 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[48]) - { - data << *FarsightObject; - } if (changesMask[49]) { - data << *SummonedBattlePetGUID; + data << *FarsightObject; } if (changesMask[50]) { - data << uint64(Coinage); + data << *SummonedBattlePetGUID; } if (changesMask[51]) { - data << uint64(AccountBankCoinage); + data << uint64(Coinage); } if (changesMask[52]) { - data << int32(XP); + data << uint64(AccountBankCoinage); } if (changesMask[53]) { - data << int32(NextLevelXP); + data << int32(XP); } if (changesMask[54]) { - data << int32(TrialXP); + data << int32(NextLevelXP); } if (changesMask[55]) { - Skill->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << int32(TrialXP); } if (changesMask[56]) { - data << int32(CharacterPoints); + Skill->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } if (changesMask[57]) { - data << int32(MaxTalentTiers); + data << int32(CharacterPoints); } if (changesMask[58]) { - data << uint32(TrackCreatureMask); + data << int32(MaxTalentTiers); } if (changesMask[59]) { - data << float(MainhandExpertise); + data << uint32(TrackCreatureMask); } if (changesMask[60]) { - data << float(OffhandExpertise); + data << float(MainhandExpertise); } if (changesMask[61]) { - data << float(RangedExpertise); + data << float(OffhandExpertise); } if (changesMask[62]) { - data << float(CombatRatingExpertise); + data << float(RangedExpertise); } if (changesMask[63]) { - data << float(BlockPercentage); + data << float(CombatRatingExpertise); } if (changesMask[64]) { - data << float(DodgePercentage); + data << float(BlockPercentage); } if (changesMask[65]) { - data << float(DodgePercentageFromAttribute); + data << float(DodgePercentage); } if (changesMask[66]) { - data << float(ParryPercentage); + data << float(DodgePercentageFromAttribute); } if (changesMask[67]) { - data << float(ParryPercentageFromAttribute); + data << float(ParryPercentage); } if (changesMask[68]) { - data << float(CritPercentage); + data << float(ParryPercentageFromAttribute); } if (changesMask[69]) { - data << float(RangedCritPercentage); + data << float(CritPercentage); } } if (changesMask[70]) { if (changesMask[71]) { - data << float(OffhandCritPercentage); + data << float(RangedCritPercentage); } if (changesMask[72]) { - data << float(SpellCritPercentage); + data << float(OffhandCritPercentage); } if (changesMask[73]) { - data << int32(ShieldBlock); + data << float(SpellCritPercentage); } if (changesMask[74]) { - data << float(ShieldBlockCritPercentage); + data << int32(ShieldBlock); } if (changesMask[75]) { - data << float(Mastery); + data << float(ShieldBlockCritPercentage); } if (changesMask[76]) { - data << float(Speed); + data << float(Mastery); } if (changesMask[77]) { - data << float(Avoidance); + data << float(Speed); } if (changesMask[78]) { - data << float(Sturdiness); + data << float(Avoidance); } if (changesMask[79]) { - data << int32(Versatility); + data << float(Sturdiness); } if (changesMask[80]) { - data << float(VersatilityBonus); + data << int32(Versatility); } if (changesMask[81]) { - data << float(PvpPowerDamage); + data << float(VersatilityBonus); } if (changesMask[82]) { - data << float(PvpPowerHealing); + data << float(PvpPowerDamage); } if (changesMask[83]) { - BitVectors->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << float(PvpPowerHealing); } if (changesMask[84]) { - data << int32(ModHealingDonePos); + BitVectors->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } if (changesMask[85]) { - data << float(ModHealingPercent); + data << int32(ModHealingDonePos); } if (changesMask[86]) { - data << float(ModPeriodicHealingDonePercent); + data << float(ModHealingPercent); } if (changesMask[87]) { - data << float(ModSpellPowerPercent); + data << float(ModPeriodicHealingDonePercent); } if (changesMask[88]) { - data << float(ModResiliencePercent); + data << float(ModSpellPowerPercent); } if (changesMask[89]) { - data << float(OverrideSpellPowerByAPPercent); + data << float(ModResiliencePercent); } if (changesMask[90]) { - data << float(OverrideAPBySpellPowerPercent); + data << float(OverrideSpellPowerByAPPercent); } if (changesMask[91]) { - data << int32(ModTargetResistance); + data << float(OverrideAPBySpellPowerPercent); } if (changesMask[92]) { - data << int32(ModTargetPhysicalResistance); + data << int32(ModTargetResistance); } if (changesMask[93]) { - data << uint32(LocalFlags); + data << int32(ModTargetPhysicalResistance); } if (changesMask[94]) { - data << uint8(GrantableLevels); + data << uint32(LocalFlags); } if (changesMask[95]) { - data << uint8(MultiActionBars); + data << uint8(GrantableLevels); } if (changesMask[96]) { - data << uint8(LifetimeMaxRank); + data << uint8(MultiActionBars); } if (changesMask[97]) { - data << uint8(NumRespecs); + data << uint8(LifetimeMaxRank); } if (changesMask[98]) { - data << uint32(PvpMedals); + data << uint8(NumRespecs); } if (changesMask[99]) { - data << uint16(TodayHonorableKills); + data << uint32(PvpMedals); } if (changesMask[100]) { - data << uint16(YesterdayHonorableKills); + data << uint16(TodayHonorableKills); } if (changesMask[101]) { - data << uint32(LifetimeHonorableKills); + data << uint16(YesterdayHonorableKills); } } if (changesMask[102]) { if (changesMask[103]) { - data << int32(WatchedFactionIndex); + data << uint32(LifetimeHonorableKills); } if (changesMask[104]) { - data << int32(MaxLevel); + data << int32(WatchedFactionIndex); } if (changesMask[105]) { - data << int32(ScalingPlayerLevelDelta); + data << int32(MaxLevel); } if (changesMask[106]) { - data << int32(MaxCreatureScalingLevel); + data << int32(ScalingPlayerLevelDelta); } if (changesMask[107]) { - data << int32(PetSpellPower); + data << int32(MaxCreatureScalingLevel); } if (changesMask[108]) { - data << float(UiHitModifier); + data << int32(PetSpellPower); } if (changesMask[109]) { - data << float(UiSpellHitModifier); + data << float(UiHitModifier); } if (changesMask[110]) { - data << int32(HomeRealmTimeOffset); + data << float(UiSpellHitModifier); } if (changesMask[111]) { - data << float(ModPetHaste); + data << int32(HomeRealmTimeOffset); } if (changesMask[112]) { - data << int8(JailersTowerLevelMax); + data << float(ModPetHaste); } if (changesMask[113]) { - data << int8(JailersTowerLevel); + data << int8(JailersTowerLevelMax); } if (changesMask[114]) { - data << uint8(LocalRegenFlags); + data << int8(JailersTowerLevel); } if (changesMask[115]) { - data << uint8(AuraVision); + data << uint8(LocalRegenFlags); } if (changesMask[116]) { - data << uint8(NumBackpackSlots); + data << uint8(AuraVision); } if (changesMask[117]) { - data << int32(OverrideSpellsID); + data << uint8(NumBackpackSlots); } if (changesMask[118]) { - data << uint16(LootSpecID); + data << int32(OverrideSpellsID); } if (changesMask[119]) { - data << uint32(OverrideZonePVPType); + data << uint16(LootSpecID); } if (changesMask[120]) { - data << int32(Honor); + data << uint32(OverrideZonePVPType); } if (changesMask[121]) { - data << int32(HonorNextLevel); + data << int32(Honor); } if (changesMask[122]) { - data << int32(PerksProgramCurrency); + data << int32(HonorNextLevel); } if (changesMask[123]) { - data << uint8(NumBankSlots); + data << int32(PerksProgramCurrency); } if (changesMask[124]) { - data << uint8(NumAccountBankTabs); + data << uint8(NumBankSlots); } - if (changesMask[129]) + if (changesMask[125]) { - data << int32(UiChromieTimeExpansionID); + data << uint8(NumCharacterBankTabs); } - if (changesMask[130]) + if (changesMask[126]) { - data << int32(TimerunningSeasonID); + data << uint8(NumAccountBankTabs); } if (changesMask[131]) { - data << int32(TransportServerTime); + data << int32(UiChromieTimeExpansionID); } if (changesMask[132]) { - data << uint32(WeeklyRewardsPeriodSinceOrigin); + data << int32(TimerunningSeasonID); } if (changesMask[133]) { - data << int16(DEBUGSoulbindConduitRank); + data << int32(TransportServerTime); } } if (changesMask[134]) { + if (changesMask[135]) + { + data << uint32(WeeklyRewardsPeriodSinceOrigin); + } if (changesMask[136]) { + data << int16(DEBUGSoulbindConduitRank); + } + if (changesMask[138]) + { data << uint32(ActiveCombatTraitConfigID); } - if (changesMask[137]) + if (changesMask[139]) { data << int32(ItemUpgradeHighOnehandWeaponItemID); } - if (changesMask[138]) + if (changesMask[140]) { data << int32(ItemUpgradeHighFingerItemID); } - if (changesMask[139]) + if (changesMask[141]) { data << float(ItemUpgradeHighFingerWatermark); } - if (changesMask[140]) + if (changesMask[142]) { data << int32(ItemUpgradeHighTrinketItemID); } - if (changesMask[141]) + if (changesMask[143]) { data << float(ItemUpgradeHighTrinketWatermark); } - if (changesMask[142]) + if (changesMask[144]) { data << uint64(LootHistoryInstanceID); } - if (changesMask[144]) + if (changesMask[146]) { data << uint8(RequiredMountCapabilityFlags); } @@ -6163,183 +6359,181 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo data.WriteBits(PetStable.has_value(), 1); data.WriteBits(WalkInData.has_value(), 1); data.WriteBits(DelveData.has_value(), 1); + data.WriteBits(ChallengeModeData.has_value(), 1); } data.FlushBits(); if (changesMask[102]) { - if (changesMask[125]) + if (changesMask[127]) { ResearchHistory->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[127]) + if (changesMask[129]) { if (QuestSession.has_value()) { QuestSession->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } - if (changesMask[126]) + if (changesMask[128]) { data << *FrozenPerksVendorItem; } - if (changesMask[128]) + if (changesMask[130]) { Field_1410->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } if (changesMask[134]) { - if (changesMask[135]) + if (changesMask[137]) { data << *DungeonScore; } - if (changesMask[143]) + if (changesMask[145]) { if (PetStable.has_value()) { PetStable->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } - if (changesMask[145]) + if (changesMask[147]) { if (WalkInData.has_value()) { WalkInData->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } - if (changesMask[146]) + if (changesMask[148]) { if (DelveData.has_value()) { DelveData->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } + if (changesMask[149]) + { + if (ChallengeModeData.has_value()) + { + ChallengeModeData->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } } - if (changesMask[147]) + if (changesMask[150]) { - for (uint32 i = 0; i < 232; ++i) + for (uint32 i = 0; i < 105; ++i) { - if (changesMask[148 + i]) + if (changesMask[151 + i]) { data << InvSlots[i]; } } } - if (changesMask[380]) + if (changesMask[256]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[381 + i]) + if (changesMask[257 + i]) { RestInfo[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[383]) + if (changesMask[259]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[384 + i]) + if (changesMask[260 + i]) { data << int32(ModDamageDonePos[i]); } - if (changesMask[391 + i]) + if (changesMask[267 + i]) { data << int32(ModDamageDoneNeg[i]); } - if (changesMask[398 + i]) + if (changesMask[274 + i]) { data << float(ModDamageDonePercent[i]); } - if (changesMask[405 + i]) + if (changesMask[281 + i]) { data << float(ModHealingDonePercent[i]); } } } - if (changesMask[412]) + if (changesMask[288]) { for (uint32 i = 0; i < 3; ++i) { - if (changesMask[413 + i]) + if (changesMask[289 + i]) { data << float(WeaponDmgMultipliers[i]); } - if (changesMask[416 + i]) + if (changesMask[292 + i]) { data << float(WeaponAtkSpeedMultipliers[i]); } } } - if (changesMask[419]) + if (changesMask[295]) { for (uint32 i = 0; i < 12; ++i) { - if (changesMask[420 + i]) + if (changesMask[296 + i]) { data << uint32(BuybackPrice[i]); } - if (changesMask[432 + i]) + if (changesMask[308 + i]) { data << int64(BuybackTimestamp[i]); } } } - if (changesMask[444]) + if (changesMask[320]) { for (uint32 i = 0; i < 32; ++i) { - if (changesMask[445 + i]) + if (changesMask[321 + i]) { data << int32(CombatRatings[i]); } } } - if (changesMask[477]) + if (changesMask[353]) { for (uint32 i = 0; i < 4; ++i) { - if (changesMask[478 + i]) + if (changesMask[354 + i]) { data << uint32(NoReagentCostMask[i]); } } } - if (changesMask[482]) + if (changesMask[358]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[483 + i]) + if (changesMask[359 + i]) { data << int32(ProfessionSkillLine[i]); } } } - if (changesMask[485]) + if (changesMask[361]) { for (uint32 i = 0; i < 5; ++i) { - if (changesMask[486 + i]) + if (changesMask[362 + i]) { data << uint32(BagSlotFlags[i]); } } } - if (changesMask[491]) - { - for (uint32 i = 0; i < 7; ++i) - { - if (changesMask[492 + i]) - { - data << uint32(BankBagSlotFlags[i]); - } - } - } - if (changesMask[499]) + if (changesMask[367]) { for (uint32 i = 0; i < 17; ++i) { - if (changesMask[500 + i]) + if (changesMask[368 + i]) { data << float(ItemUpgradeHighWatermark[i]); } @@ -6392,6 +6586,7 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(CharacterRestrictions); Base::ClearChangesMask(TraitConfigs); Base::ClearChangesMask(CraftingOrders); + Base::ClearChangesMask(CharacterBankTabSettings); Base::ClearChangesMask(AccountBankTabSettings); Base::ClearChangesMask(FarsightObject); Base::ClearChangesMask(SummonedBattlePetGUID); @@ -6467,6 +6662,7 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(HonorNextLevel); Base::ClearChangesMask(PerksProgramCurrency); Base::ClearChangesMask(NumBankSlots); + Base::ClearChangesMask(NumCharacterBankTabs); Base::ClearChangesMask(NumAccountBankTabs); Base::ClearChangesMask(ResearchHistory); Base::ClearChangesMask(FrozenPerksVendorItem); @@ -6489,6 +6685,7 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(RequiredMountCapabilityFlags); Base::ClearChangesMask(WalkInData); Base::ClearChangesMask(DelveData); + Base::ClearChangesMask(ChallengeModeData); Base::ClearChangesMask(InvSlots); Base::ClearChangesMask(RestInfo); Base::ClearChangesMask(ModDamageDonePos); @@ -6503,11 +6700,44 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(NoReagentCostMask); Base::ClearChangesMask(ProfessionSkillLine); Base::ClearChangesMask(BagSlotFlags); - Base::ClearChangesMask(BankBagSlotFlags); Base::ClearChangesMask(ItemUpgradeHighWatermark); _changesMask.ResetAll(); } +void GameObjectAssistActionData::WriteCreate(ByteBuffer& data, GameObject const* owner, Player const* receiver) const +{ + data.WriteBits(PlayerName.size(), 6); + data.WriteBits(MonsterName.size() + 1, 11); + data << uint32(VirtualRealmAddress); + data << uint8(Sex); + data << int64(Time); + data << int32(DelveTier); + data << WorldPackets::SizedString::Data(PlayerName); + data << WorldPackets::SizedCString::Data(MonsterName); +} + +void GameObjectAssistActionData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, GameObject const* owner, Player const* receiver) const +{ + data.WriteBits(PlayerName.size(), 6); + data.WriteBits(MonsterName.size() + 1, 11); + data << uint32(VirtualRealmAddress); + data << uint8(Sex); + data << int64(Time); + data << int32(DelveTier); + data << WorldPackets::SizedString::Data(PlayerName); + data << WorldPackets::SizedCString::Data(MonsterName); +} + +bool GameObjectAssistActionData::operator==(GameObjectAssistActionData const& right) const +{ + return PlayerName == right.PlayerName + && MonsterName == right.MonsterName + && VirtualRealmAddress == right.VirtualRealmAddress + && Sex == right.Sex + && Time == right.Time + && DelveTier == right.DelveTier; +} + void GameObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const { ViewerDependentValue<StateWorldEffectIDsTag>::value_type stateWorldEffectIDs = {}; @@ -6552,6 +6782,12 @@ void GameObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie { data << int32(WorldEffects[i]); } + data.WriteBits(AssistActionData.has_value(), 1); + data.FlushBits(); + if (AssistActionData.has_value()) + { + AssistActionData->WriteCreate(data, owner, receiver); + } } void GameObjectData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const @@ -6561,7 +6797,7 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, GameObject const* owner, Player const* receiver) const { - data.WriteBits(changesMask.GetBlock(0), 25); + data.WriteBits(changesMask.GetBlock(0), 26); ViewerDependentValue<StateWorldEffectIDsTag>::value_type stateWorldEffectIDs = {}; @@ -6705,6 +6941,15 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool { data << uint32(UiWidgetItemUnknown1000); } + data.WriteBits(AssistActionData.has_value(), 1); + data.FlushBits(); + if (changesMask[25]) + { + if (AssistActionData.has_value()) + { + AssistActionData->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } } } @@ -6734,6 +6979,7 @@ void GameObjectData::ClearChangesMask() Base::ClearChangesMask(UiWidgetItemID); Base::ClearChangesMask(UiWidgetItemQuality); Base::ClearChangesMask(UiWidgetItemUnknown1000); + Base::ClearChangesMask(AssistActionData); _changesMask.ResetAll(); } @@ -7044,6 +7290,514 @@ void VisualAnim::ClearChangesMask() _changesMask.ResetAll(); } +void ForceSetAreaTriggerPositionAndRotation::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << TriggerGUID; + data << Position; + data << float(Rotation.x); + data << float(Rotation.y); + data << float(Rotation.z); + data << float(Rotation.w); +} + +void ForceSetAreaTriggerPositionAndRotation::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + data << TriggerGUID; + data << Position; + data << float(Rotation.x); + data << float(Rotation.y); + data << float(Rotation.z); + data << float(Rotation.w); +} + +bool ForceSetAreaTriggerPositionAndRotation::operator==(ForceSetAreaTriggerPositionAndRotation const& right) const +{ + return TriggerGUID == right.TriggerGUID + && Position == right.Position + && Rotation == right.Rotation; +} + +void AreaTriggerSplineCalculator::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data.WriteBits(Points.size(), 16); + data.WriteBit(Catmullrom); + for (uint32 i = 0; i < Points.size(); ++i) + { + data << Points[i]; + } + data.FlushBits(); +} + +void AreaTriggerSplineCalculator::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 3); + + if (changesMask[0]) + { + if (changesMask[1]) + { + data.WriteBit(Catmullrom); + } + if (changesMask[2]) + { + if (!ignoreChangesMask) + Points.WriteUpdateMask(data, 16); + else + WriteCompleteDynamicFieldUpdateMask(Points.size(), data, 16); + } + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[2]) + { + for (uint32 i = 0; i < Points.size(); ++i) + { + if (Points.HasChanged(i) || ignoreChangesMask) + { + data << Points[i]; + } + } + } + } + data.FlushBits(); +} + +void AreaTriggerSplineCalculator::ClearChangesMask() +{ + Base::ClearChangesMask(Catmullrom); + Base::ClearChangesMask(Points); + _changesMask.ResetAll(); +} + +void AreaTriggerOrbit::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << *Center; + data << float(Radius); + data << float(InitialAngle); + data << float(BlendFromRadius); + data << int32(ExtraTimeForBlending); + data.WriteBit(CounterClockwise); + data.FlushBits(); +} + +void AreaTriggerOrbit::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 7); + + if (changesMask[0]) + { + if (changesMask[1]) + { + data.WriteBit(CounterClockwise); + } + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[2]) + { + data << *Center; + } + if (changesMask[3]) + { + data << float(Radius); + } + if (changesMask[4]) + { + data << float(InitialAngle); + } + if (changesMask[5]) + { + data << float(BlendFromRadius); + } + if (changesMask[6]) + { + data << int32(ExtraTimeForBlending); + } + } + data.FlushBits(); +} + +void AreaTriggerOrbit::ClearChangesMask() +{ + Base::ClearChangesMask(CounterClockwise); + Base::ClearChangesMask(Center); + Base::ClearChangesMask(Radius); + Base::ClearChangesMask(InitialAngle); + Base::ClearChangesMask(BlendFromRadius); + Base::ClearChangesMask(ExtraTimeForBlending); + _changesMask.ResetAll(); +} + +void AreaTriggerMovementScript::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << int32(SpellScriptID); + data << *Center; + data << uint32(CreationTime); +} + +void AreaTriggerMovementScript::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 4); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << int32(SpellScriptID); + } + if (changesMask[2]) + { + data << *Center; + } + if (changesMask[3]) + { + data << uint32(CreationTime); + } + } +} + +void AreaTriggerMovementScript::ClearChangesMask() +{ + Base::ClearChangesMask(SpellScriptID); + Base::ClearChangesMask(Center); + Base::ClearChangesMask(CreationTime); + _changesMask.ResetAll(); +} + +void AreaTriggerSphere::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << float(Radius); + data << float(RadiusTarget); +} + +void AreaTriggerSphere::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 3); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << float(Radius); + } + if (changesMask[2]) + { + data << float(RadiusTarget); + } + } +} + +void AreaTriggerSphere::ClearChangesMask() +{ + Base::ClearChangesMask(Radius); + Base::ClearChangesMask(RadiusTarget); + _changesMask.ResetAll(); +} + +void AreaTriggerBox::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << *Extents; + data << *ExtentsTarget; +} + +void AreaTriggerBox::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 3); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << *Extents; + } + if (changesMask[2]) + { + data << *ExtentsTarget; + } + } +} + +void AreaTriggerBox::ClearChangesMask() +{ + Base::ClearChangesMask(Extents); + Base::ClearChangesMask(ExtentsTarget); + _changesMask.ResetAll(); +} + +void AreaTriggerPolygon::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << uint32(Vertices.size()); + data << uint32(VerticesTarget.size()); + data << float(Height); + data << float(HeightTarget); + for (uint32 i = 0; i < Vertices.size(); ++i) + { + data << Vertices[i]; + } + for (uint32 i = 0; i < VerticesTarget.size(); ++i) + { + data << VerticesTarget[i]; + } +} + +void AreaTriggerPolygon::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 5); + + if (changesMask[0]) + { + if (changesMask[1]) + { + if (!ignoreChangesMask) + Vertices.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(Vertices.size(), data); + } + if (changesMask[2]) + { + if (!ignoreChangesMask) + VerticesTarget.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(VerticesTarget.size(), data); + } + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + for (uint32 i = 0; i < Vertices.size(); ++i) + { + if (Vertices.HasChanged(i) || ignoreChangesMask) + { + data << Vertices[i]; + } + } + } + if (changesMask[2]) + { + for (uint32 i = 0; i < VerticesTarget.size(); ++i) + { + if (VerticesTarget.HasChanged(i) || ignoreChangesMask) + { + data << VerticesTarget[i]; + } + } + } + if (changesMask[3]) + { + data << float(Height); + } + if (changesMask[4]) + { + data << float(HeightTarget); + } + } +} + +void AreaTriggerPolygon::ClearChangesMask() +{ + Base::ClearChangesMask(Vertices); + Base::ClearChangesMask(VerticesTarget); + Base::ClearChangesMask(Height); + Base::ClearChangesMask(HeightTarget); + _changesMask.ResetAll(); +} + +void AreaTriggerCylinder::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << float(Radius); + data << float(RadiusTarget); + data << float(Height); + data << float(HeightTarget); + data << float(LocationZOffset); + data << float(LocationZOffsetTarget); +} + +void AreaTriggerCylinder::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 7); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << float(Radius); + } + if (changesMask[2]) + { + data << float(RadiusTarget); + } + if (changesMask[3]) + { + data << float(Height); + } + if (changesMask[4]) + { + data << float(HeightTarget); + } + if (changesMask[5]) + { + data << float(LocationZOffset); + } + if (changesMask[6]) + { + data << float(LocationZOffsetTarget); + } + } +} + +void AreaTriggerCylinder::ClearChangesMask() +{ + Base::ClearChangesMask(Radius); + Base::ClearChangesMask(RadiusTarget); + Base::ClearChangesMask(Height); + Base::ClearChangesMask(HeightTarget); + Base::ClearChangesMask(LocationZOffset); + Base::ClearChangesMask(LocationZOffsetTarget); + _changesMask.ResetAll(); +} + +void AreaTriggerDisk::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << float(InnerRadius); + data << float(InnerRadiusTarget); + data << float(OuterRadius); + data << float(OuterRadiusTarget); + data << float(Height); + data << float(HeightTarget); + data << float(LocationZOffset); + data << float(LocationZOffsetTarget); +} + +void AreaTriggerDisk::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 9); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << float(InnerRadius); + } + if (changesMask[2]) + { + data << float(InnerRadiusTarget); + } + if (changesMask[3]) + { + data << float(OuterRadius); + } + if (changesMask[4]) + { + data << float(OuterRadiusTarget); + } + if (changesMask[5]) + { + data << float(Height); + } + if (changesMask[6]) + { + data << float(HeightTarget); + } + if (changesMask[7]) + { + data << float(LocationZOffset); + } + if (changesMask[8]) + { + data << float(LocationZOffsetTarget); + } + } +} + +void AreaTriggerDisk::ClearChangesMask() +{ + Base::ClearChangesMask(InnerRadius); + Base::ClearChangesMask(InnerRadiusTarget); + Base::ClearChangesMask(OuterRadius); + Base::ClearChangesMask(OuterRadiusTarget); + Base::ClearChangesMask(Height); + Base::ClearChangesMask(HeightTarget); + Base::ClearChangesMask(LocationZOffset); + Base::ClearChangesMask(LocationZOffsetTarget); + _changesMask.ResetAll(); +} + +void AreaTriggerBoundedPlane::WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const +{ + data << *Extents; + data << *ExtentsTarget; +} + +void AreaTriggerBoundedPlane::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 3); + + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + data << *Extents; + } + if (changesMask[2]) + { + data << *ExtentsTarget; + } + } +} + +void AreaTriggerBoundedPlane::ClearChangesMask() +{ + Base::ClearChangesMask(Extents); + Base::ClearChangesMask(ExtentsTarget); + _changesMask.ResetAll(); +} + void AreaTriggerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const { OverrideScaleCurve->WriteCreate(data, owner, receiver); @@ -7059,20 +7813,72 @@ void AreaTriggerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi data << float(BoundsRadius2D); data << uint32(DecalPropertiesID); data << *CreatingEffectGUID; - data << uint32(NumUnitsInside); - data << uint32(NumPlayersInside); data << *OrbitPathTarget; data << *RollPitchYaw; data << int32(PositionalSoundKitID); + data << uint32(MovementStartTime); + data << uint32(CreationTime); + data << float(ZOffset); + data << uint32(Flags); + data << uint32(ScaleCurveId); + data << uint32(FacingCurveId); + data << uint32(MorphCurveId); + data << uint32(MoveCurveId); + data << float(Facing); + data << int32(PathType); + data << uint8(ShapeType); + if (PathType == 3) + { + PathData.Get<UF::AreaTriggerMovementScript>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 0) + { + ShapeData.Get<UF::AreaTriggerSphere>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 1) + { + ShapeData.Get<UF::AreaTriggerBox>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 3) + { + ShapeData.Get<UF::AreaTriggerPolygon>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 4) + { + ShapeData.Get<UF::AreaTriggerCylinder>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 7) + { + ShapeData.Get<UF::AreaTriggerDisk>()->WriteCreate(data, owner, receiver); + } + if (ShapeType == 8) + { + ShapeData.Get<UF::AreaTriggerBoundedPlane>()->WriteCreate(data, owner, receiver); + } ExtraScaleCurve->WriteCreate(data, owner, receiver); data.FlushBits(); - data.WriteBit(HeightIgnoresScale); - data.WriteBit(Field_261); + data.WriteBits(TargetRollPitchYaw.has_value(), 1); + data.WriteBits(ForcedPositionAndRotation.has_value(), 1); OverrideMoveCurveX->WriteCreate(data, owner, receiver); + if (TargetRollPitchYaw.has_value()) + { + data << *TargetRollPitchYaw; + } + if (ForcedPositionAndRotation.has_value()) + { + ForcedPositionAndRotation->WriteCreate(data, owner, receiver); + } OverrideMoveCurveY->WriteCreate(data, owner, receiver); OverrideMoveCurveZ->WriteCreate(data, owner, receiver); VisualAnim->WriteCreate(data, owner, receiver); - data.FlushBits(); + if (PathType == 0) + { + PathData.Get<UF::AreaTriggerSplineCalculator>()->WriteCreate(data, owner, receiver); + } + if (PathType == 1) + { + PathData.Get<UF::AreaTriggerOrbit>()->WriteCreate(data, owner, receiver); + } } void AreaTriggerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const @@ -7082,122 +7888,232 @@ void AreaTriggerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi void AreaTriggerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, AreaTrigger const* owner, Player const* receiver) const { - data.WriteBits(changesMask.GetBlock(0), 26); + data << uint32(changesMask.GetBlock(0)); + data.WriteBits(changesMask.GetBlock(1), 4); + data.FlushBits(); if (changesMask[0]) { if (changesMask[1]) { - data.WriteBit(HeightIgnoresScale); + OverrideScaleCurve->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[2]) + if (changesMask[6]) { - data.WriteBit(Field_261); + data << *Caster; } - } - data.FlushBits(); - if (changesMask[0]) - { - if (changesMask[3]) + if (changesMask[7]) { - OverrideScaleCurve->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << uint32(Duration); } if (changesMask[8]) { - data << *Caster; + data << uint32(TimeToTarget); } if (changesMask[9]) { - data << uint32(Duration); + data << uint32(TimeToTargetScale); } if (changesMask[10]) { - data << uint32(TimeToTarget); + data << uint32(TimeToTargetExtraScale); } if (changesMask[11]) { - data << uint32(TimeToTargetScale); + data << uint32(TimeToTargetPos); } if (changesMask[12]) { - data << uint32(TimeToTargetExtraScale); + data << int32(SpellID); } if (changesMask[13]) { - data << uint32(TimeToTargetPos); + data << int32(SpellForVisuals); } if (changesMask[14]) { - data << int32(SpellID); + SpellVisual->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } if (changesMask[15]) { - data << int32(SpellForVisuals); + data << float(BoundsRadius2D); } if (changesMask[16]) { - SpellVisual->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << uint32(DecalPropertiesID); } if (changesMask[17]) { - data << float(BoundsRadius2D); + data << *CreatingEffectGUID; } if (changesMask[18]) { - data << uint32(DecalPropertiesID); + data << *OrbitPathTarget; } if (changesMask[19]) { - data << *CreatingEffectGUID; + data << *RollPitchYaw; } if (changesMask[20]) { - data << uint32(NumUnitsInside); + data << int32(PositionalSoundKitID); } if (changesMask[21]) { - data << uint32(NumPlayersInside); + data << uint32(MovementStartTime); } if (changesMask[22]) { - data << *OrbitPathTarget; + data << uint32(CreationTime); } if (changesMask[23]) { - data << *RollPitchYaw; + data << float(ZOffset); } - if (changesMask[24]) + if (changesMask[25]) { - data << int32(PositionalSoundKitID); + data << uint32(Flags); } - if (changesMask[4]) + if (changesMask[27]) + { + data << uint32(ScaleCurveId); + } + if (changesMask[28]) + { + data << uint32(FacingCurveId); + } + if (changesMask[29]) + { + data << uint32(MorphCurveId); + } + if (changesMask[30]) + { + data << uint32(MoveCurveId); + } + if (changesMask[31]) + { + data << float(Facing); + } + } + if (changesMask[32]) + { + if (changesMask[34]) + { + data << int32(PathType); + } + if (changesMask[35]) + { + data << uint8(ShapeType); + } + if (changesMask[34]) + { + if (PathType == 3) + { + PathData.Get<UF::AreaTriggerMovementScript>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + if (changesMask[35]) + { + if (ShapeType == 0) + { + ShapeData.Get<UF::AreaTriggerSphere>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (ShapeType == 1) + { + ShapeData.Get<UF::AreaTriggerBox>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (ShapeType == 3) + { + ShapeData.Get<UF::AreaTriggerPolygon>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (ShapeType == 4) + { + ShapeData.Get<UF::AreaTriggerCylinder>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (ShapeType == 7) + { + ShapeData.Get<UF::AreaTriggerDisk>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (ShapeType == 8) + { + ShapeData.Get<UF::AreaTriggerBoundedPlane>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + } + if (changesMask[0]) + { + if (changesMask[2]) { ExtraScaleCurve->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[5]) + } + data.FlushBits(); + if (changesMask[0]) + { + data.WriteBits(TargetRollPitchYaw.has_value(), 1); + } + if (changesMask[32]) + { + data.WriteBits(ForcedPositionAndRotation.has_value(), 1); + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[3]) { OverrideMoveCurveX->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[6]) + if (changesMask[24]) + { + if (TargetRollPitchYaw.has_value()) + { + data << *TargetRollPitchYaw; + } + } + } + if (changesMask[32]) + { + if (changesMask[33]) + { + if (ForcedPositionAndRotation.has_value()) + { + ForcedPositionAndRotation->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + } + if (changesMask[0]) + { + if (changesMask[4]) { OverrideMoveCurveY->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[7]) + if (changesMask[5]) { OverrideMoveCurveZ->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[25]) + if (changesMask[26]) { VisualAnim->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } - data.FlushBits(); + if (changesMask[32]) + { + if (changesMask[34]) + { + if (PathType == 0) + { + PathData.Get<UF::AreaTriggerSplineCalculator>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (PathType == 1) + { + PathData.Get<UF::AreaTriggerOrbit>()->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + } } void AreaTriggerData::ClearChangesMask() { - Base::ClearChangesMask(HeightIgnoresScale); - Base::ClearChangesMask(Field_261); Base::ClearChangesMask(OverrideScaleCurve); Base::ClearChangesMask(ExtraScaleCurve); Base::ClearChangesMask(OverrideMoveCurveX); @@ -7215,12 +8131,25 @@ void AreaTriggerData::ClearChangesMask() Base::ClearChangesMask(BoundsRadius2D); Base::ClearChangesMask(DecalPropertiesID); Base::ClearChangesMask(CreatingEffectGUID); - Base::ClearChangesMask(NumUnitsInside); - Base::ClearChangesMask(NumPlayersInside); Base::ClearChangesMask(OrbitPathTarget); Base::ClearChangesMask(RollPitchYaw); Base::ClearChangesMask(PositionalSoundKitID); + Base::ClearChangesMask(MovementStartTime); + Base::ClearChangesMask(CreationTime); + Base::ClearChangesMask(ZOffset); + Base::ClearChangesMask(TargetRollPitchYaw); + Base::ClearChangesMask(Flags); Base::ClearChangesMask(VisualAnim); + Base::ClearChangesMask(ScaleCurveId); + Base::ClearChangesMask(FacingCurveId); + Base::ClearChangesMask(MorphCurveId); + Base::ClearChangesMask(MoveCurveId); + Base::ClearChangesMask(Facing); + Base::ClearChangesMask(ForcedPositionAndRotation); + Base::ClearChangesMask(PathType); + Base::ClearChangesMask(ShapeType); + Base::ClearChangesMask(PathData); + Base::ClearChangesMask(ShapeData); _changesMask.ResetAll(); } diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index 6635950cc62..db0f1859545 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -227,6 +227,8 @@ struct UnitChannel : public IsUpdateFieldStructureTag { int32 SpellID; UF::SpellCastVisual SpellVisual; + uint32 StartTimeMs; + uint32 Duration; void WriteCreate(ByteBuffer& data, Unit const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Unit const* owner, Player const* receiver) const; @@ -258,7 +260,18 @@ struct PassiveSpellHistory : public IsUpdateFieldStructureTag bool operator!=(PassiveSpellHistory const& right) const { return !(*this == right); } }; -struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<222> +struct UnitAssistActionData : public IsUpdateFieldStructureTag, public HasChangesMask<4> +{ + UpdateField<uint8, 0, 1> Type; + UpdateField<std::string, 0, 2> PlayerName; + UpdateField<uint32, 0, 3> VirtualRealmAddress; + + void WriteCreate(ByteBuffer& data, Unit const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Unit const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<223> { UpdateField<bool, 0, 1> Field_314; UpdateField<std::vector<uint32>, 0, 2> StateWorldEffectIDs; @@ -406,19 +419,20 @@ struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<222> UpdateField<float, 128, 132> Field_31C; UpdateField<float, 128, 133> Field_320; // Soft targeting related? When UnitFlags3 & 0x40000000 is set, increases some range check using CombatReach by this amount UpdateField<ObjectGuid, 128, 134> NameplateAttachToGUID; // When set, nameplate of this unit will instead appear on that object - UpdateFieldArray<int32, 10, 135, 136> Power; - UpdateFieldArray<int32, 10, 135, 146> MaxPower; - UpdateFieldArray<float, 10, 135, 156> PowerRegenFlatModifier; - UpdateFieldArray<float, 10, 135, 166> PowerRegenInterruptedFlatModifier; - UpdateFieldArray<UF::VisibleItem, 3, 176, 177> VirtualItems; - UpdateFieldArray<uint32, 2, 180, 181> AttackRoundBaseTime; - UpdateFieldArray<int32, 4, 183, 184> Stats; - UpdateFieldArray<int32, 4, 183, 188> StatPosBuff; - UpdateFieldArray<int32, 4, 183, 192> StatNegBuff; - UpdateFieldArray<int32, 4, 183, 196> StatSupportBuff; - UpdateFieldArray<int32, 7, 200, 201> Resistances; - UpdateFieldArray<int32, 7, 200, 208> BonusResistanceMods; - UpdateFieldArray<int32, 7, 200, 215> ManaCostModifier; + OptionalUpdateField<UF::UnitAssistActionData, 128, 135> AssistActionData; + UpdateFieldArray<int32, 10, 136, 137> Power; + UpdateFieldArray<int32, 10, 136, 147> MaxPower; + UpdateFieldArray<float, 10, 136, 157> PowerRegenFlatModifier; + UpdateFieldArray<float, 10, 136, 167> PowerRegenInterruptedFlatModifier; + UpdateFieldArray<UF::VisibleItem, 3, 177, 178> VirtualItems; + UpdateFieldArray<uint32, 2, 181, 182> AttackRoundBaseTime; + UpdateFieldArray<int32, 4, 184, 185> Stats; + UpdateFieldArray<int32, 4, 184, 189> StatPosBuff; + UpdateFieldArray<int32, 4, 184, 193> StatNegBuff; + UpdateFieldArray<int32, 4, 184, 197> StatSupportBuff; + UpdateFieldArray<int32, 7, 201, 202> Resistances; + UpdateFieldArray<int32, 7, 201, 209> BonusResistanceMods; + UpdateFieldArray<int32, 7, 201, 216> ManaCostModifier; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const; @@ -499,6 +513,25 @@ struct CTROptions : public IsUpdateFieldStructureTag bool operator!=(CTROptions const& right) const { return !(*this == right); } }; +struct LeaverInfo : public IsUpdateFieldStructureTag +{ + ObjectGuid BnetAccountGUID; + float LeaveScore; + uint32 SeasonID; + uint32 TotalLeaves; + uint32 TotalSuccesses; + int32 ConsecutiveSuccesses; + int64 LastPenaltyTime; + int64 LeaverExpirationTime; + int32 Unknown_1120; + uint32 LeaverStatus; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + bool operator==(LeaverInfo const& right) const; + bool operator!=(LeaverInfo const& right) const { return !(*this == right); } +}; + struct DeclinedNames : public IsUpdateFieldStructureTag, public HasChangesMask<6> { UpdateFieldArray<std::string, 5, 0, 1> Name; @@ -521,7 +554,7 @@ struct CustomTabardInfo : public IsUpdateFieldStructureTag, public HasChangesMas void ClearChangesMask(); }; -struct PlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<322> +struct PlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<324> { UpdateField<bool, 0, 1> HasQuestSession; UpdateField<bool, 0, 2> HasLevelLink; @@ -551,29 +584,31 @@ struct PlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<322> UpdateField<int32, 0, 26> FakeInebriation; UpdateField<uint32, 0, 27> VirtualPlayerRealm; UpdateField<uint32, 0, 28> CurrentSpecID; - UpdateField<int32, 0, 29> TaxiMountAnimKitID; - UpdateField<uint8, 0, 30> CurrentBattlePetBreedQuality; - UpdateField<int32, 0, 31> HonorLevel; - UpdateField<int64, 32, 33> LogoutTime; - UpdateField<std::string, 32, 34> Name; - UpdateField<int32, 32, 35> Field_1AC; - UpdateField<int32, 32, 36> Field_1B0; - UpdateField<int32, 32, 37> CurrentBattlePetSpeciesID; - UpdateField<UF::CTROptions, 32, 38> CtrOptions; - UpdateField<int32, 32, 39> CovenantID; - UpdateField<int32, 32, 40> SoulbindID; - UpdateField<WorldPackets::MythicPlus::DungeonScoreSummary, 32, 41> DungeonScore; - UpdateField<ObjectGuid, 32, 42> SpectateTarget; - UpdateField<int32, 32, 43> Field_200; - OptionalUpdateField<UF::DeclinedNames, 32, 44> DeclinedNames; - UpdateField<UF::CustomTabardInfo, 32, 45> PersonalTabard; - UpdateFieldArray<uint8, 2, 46, 47> PartyType; - UpdateFieldArray<UF::QuestLog, 175, 49, 50> QuestLog; - UpdateFieldArray<UF::VisibleItem, 19, 225, 226> VisibleItems; - UpdateFieldArray<float, 6, 245, 246> AvgItemLevel; - UpdateFieldArray<UF::ZonePlayerForcedReaction, 32, 252, 253> ForcedReactions; - UpdateFieldArray<WorldPackets::Item::ItemInstance, 16, 285, 286> VisibleEquipableSpells; - UpdateFieldArray<uint32, 19, 302, 303> Field_3120; + UpdateField<int32, 0, 29> CurrentCombatTraitConfigSubTreeID; + UpdateField<int32, 0, 30> TaxiMountAnimKitID; + UpdateField<uint8, 0, 31> CurrentBattlePetBreedQuality; + UpdateField<int32, 32, 33> HonorLevel; + UpdateField<int64, 32, 34> LogoutTime; + UpdateField<std::string, 32, 35> Name; + UpdateField<int32, 32, 36> Field_1AC; + UpdateField<int32, 32, 37> Field_1B0; + UpdateField<int32, 32, 38> CurrentBattlePetSpeciesID; + UpdateField<UF::CTROptions, 32, 39> CtrOptions; + UpdateField<int32, 32, 40> CovenantID; + UpdateField<int32, 32, 41> SoulbindID; + UpdateField<WorldPackets::MythicPlus::DungeonScoreSummary, 32, 42> DungeonScore; + UpdateField<UF::LeaverInfo, 32, 43> LeaverInfo; + UpdateField<ObjectGuid, 32, 44> SpectateTarget; + UpdateField<int32, 32, 45> Field_200; + OptionalUpdateField<UF::DeclinedNames, 32, 46> DeclinedNames; + UpdateField<UF::CustomTabardInfo, 32, 47> PersonalTabard; + UpdateFieldArray<uint8, 2, 48, 49> PartyType; + UpdateFieldArray<UF::QuestLog, 175, 51, 52> QuestLog; + UpdateFieldArray<UF::VisibleItem, 19, 227, 228> VisibleItems; + UpdateFieldArray<float, 6, 247, 248> AvgItemLevel; + UpdateFieldArray<UF::ZonePlayerForcedReaction, 32, 254, 255> ForcedReactions; + UpdateFieldArray<WorldPackets::Item::ItemInstance, 16, 287, 288> VisibleEquipableSpells; + UpdateFieldArray<uint32, 19, 304, 305> Field_3120; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; @@ -791,6 +826,7 @@ struct TraitEntry : public IsUpdateFieldStructureTag int32 TraitNodeEntryID; int32 Rank; int32 GrantedRanks; + int32 BonusRanks; void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; @@ -1025,6 +1061,24 @@ struct DelveData : public IsUpdateFieldStructureTag bool operator!=(DelveData const& right) const { return !(*this == right); } }; +struct ChallengeModeData : public IsUpdateFieldStructureTag +{ + int32 Unknown_1120_1; + int32 Unknown_1120_2; + uint64 Unknown_1120_3; + int64 Unknown_1120_4; + ObjectGuid KeystoneOwnerGUID; + ObjectGuid LeaverGUID; + uint32 IsActive; + uint32 HasRestrictions; + uint32 CanVoteAbandon; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + bool operator==(ChallengeModeData const& right) const; + bool operator!=(ChallengeModeData const& right) const { return !(*this == right); } +}; + struct Research : public IsUpdateFieldStructureTag { int16 ResearchProjectID; @@ -1035,7 +1089,7 @@ struct Research : public IsUpdateFieldStructureTag bool operator!=(Research const& right) const { return !(*this == right); } }; -struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<517> +struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<385> { UpdateField<bool, 0, 1> BackpackAutoSortDisabled; UpdateField<bool, 0, 2> BackpackSellJunkDisabled; @@ -1043,9 +1097,9 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas UpdateField<bool, 0, 4> SortBagsRightToLeft; UpdateField<bool, 0, 5> InsertItemsLeftToRight; UpdateField<bool, 0, 6> HasPerksProgramPendingReward; - UpdateFieldArray<DynamicUpdateFieldBase<uint16>, 1, 42, 43> ResearchSites; - UpdateFieldArray<DynamicUpdateFieldBase<uint32>, 1, 44, 45> ResearchSiteProgress; - UpdateFieldArray<DynamicUpdateFieldBase<UF::Research>, 1, 46, 47> Research; + UpdateFieldArray<DynamicUpdateFieldBase<uint16>, 1, 43, 44> ResearchSites; + UpdateFieldArray<DynamicUpdateFieldBase<uint32>, 1, 45, 46> ResearchSiteProgress; + UpdateFieldArray<DynamicUpdateFieldBase<UF::Research>, 1, 47, 48> Research; DynamicUpdateField<uint64, 0, 7> KnownTitles; DynamicUpdateField<UF::PlayerDataElement, 0, 8> CharacterDataElements; DynamicUpdateField<UF::PlayerDataElement, 0, 9> AccountDataElements; @@ -1079,119 +1133,121 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas DynamicUpdateField<UF::CharacterRestriction, 0, 24> CharacterRestrictions; DynamicUpdateField<UF::TraitConfig, 32, 34> TraitConfigs; DynamicUpdateField<UF::CraftingOrder, 32, 35> CraftingOrders; - DynamicUpdateField<UF::BankTabSettings, 32, 41> AccountBankTabSettings; - UpdateField<ObjectGuid, 32, 48> FarsightObject; - UpdateField<ObjectGuid, 32, 49> SummonedBattlePetGUID; - UpdateField<uint64, 32, 50> Coinage; - UpdateField<uint64, 32, 51> AccountBankCoinage; - UpdateField<int32, 32, 52> XP; - UpdateField<int32, 32, 53> NextLevelXP; - UpdateField<int32, 32, 54> TrialXP; - UpdateField<UF::SkillInfo, 32, 55> Skill; - UpdateField<int32, 32, 56> CharacterPoints; - UpdateField<int32, 32, 57> MaxTalentTiers; - UpdateField<uint32, 32, 58> TrackCreatureMask; - UpdateField<float, 32, 59> MainhandExpertise; - UpdateField<float, 32, 60> OffhandExpertise; - UpdateField<float, 32, 61> RangedExpertise; - UpdateField<float, 32, 62> CombatRatingExpertise; - UpdateField<float, 32, 63> BlockPercentage; - UpdateField<float, 32, 64> DodgePercentage; - UpdateField<float, 32, 65> DodgePercentageFromAttribute; - UpdateField<float, 32, 66> ParryPercentage; - UpdateField<float, 32, 67> ParryPercentageFromAttribute; - UpdateField<float, 32, 68> CritPercentage; - UpdateField<float, 32, 69> RangedCritPercentage; - UpdateField<float, 70, 71> OffhandCritPercentage; - UpdateField<float, 70, 72> SpellCritPercentage; - UpdateField<int32, 70, 73> ShieldBlock; - UpdateField<float, 70, 74> ShieldBlockCritPercentage; - UpdateField<float, 70, 75> Mastery; - UpdateField<float, 70, 76> Speed; - UpdateField<float, 70, 77> Avoidance; - UpdateField<float, 70, 78> Sturdiness; - UpdateField<int32, 70, 79> Versatility; - UpdateField<float, 70, 80> VersatilityBonus; - UpdateField<float, 70, 81> PvpPowerDamage; - UpdateField<float, 70, 82> PvpPowerHealing; - UpdateField<UF::BitVectors, 70, 83> BitVectors; - UpdateField<int32, 70, 84> ModHealingDonePos; - UpdateField<float, 70, 85> ModHealingPercent; - UpdateField<float, 70, 86> ModPeriodicHealingDonePercent; - UpdateField<float, 70, 87> ModSpellPowerPercent; - UpdateField<float, 70, 88> ModResiliencePercent; - UpdateField<float, 70, 89> OverrideSpellPowerByAPPercent; - UpdateField<float, 70, 90> OverrideAPBySpellPowerPercent; - UpdateField<int32, 70, 91> ModTargetResistance; - UpdateField<int32, 70, 92> ModTargetPhysicalResistance; - UpdateField<uint32, 70, 93> LocalFlags; - UpdateField<uint8, 70, 94> GrantableLevels; - UpdateField<uint8, 70, 95> MultiActionBars; - UpdateField<uint8, 70, 96> LifetimeMaxRank; - UpdateField<uint8, 70, 97> NumRespecs; - UpdateField<uint32, 70, 98> PvpMedals; - UpdateField<uint16, 70, 99> TodayHonorableKills; - UpdateField<uint16, 70, 100> YesterdayHonorableKills; - UpdateField<uint32, 70, 101> LifetimeHonorableKills; - UpdateField<int32, 102, 103> WatchedFactionIndex; - UpdateField<int32, 102, 104> MaxLevel; - UpdateField<int32, 102, 105> ScalingPlayerLevelDelta; - UpdateField<int32, 102, 106> MaxCreatureScalingLevel; - UpdateField<int32, 102, 107> PetSpellPower; - UpdateField<float, 102, 108> UiHitModifier; - UpdateField<float, 102, 109> UiSpellHitModifier; - UpdateField<int32, 102, 110> HomeRealmTimeOffset; - UpdateField<float, 102, 111> ModPetHaste; - UpdateField<int8, 102, 112> JailersTowerLevelMax; - UpdateField<int8, 102, 113> JailersTowerLevel; - UpdateField<uint8, 102, 114> LocalRegenFlags; - UpdateField<uint8, 102, 115> AuraVision; - UpdateField<uint8, 102, 116> NumBackpackSlots; - UpdateField<int32, 102, 117> OverrideSpellsID; - UpdateField<uint16, 102, 118> LootSpecID; - UpdateField<uint32, 102, 119> OverrideZonePVPType; - UpdateField<int32, 102, 120> Honor; - UpdateField<int32, 102, 121> HonorNextLevel; - UpdateField<int32, 102, 122> PerksProgramCurrency; - UpdateField<uint8, 102, 123> NumBankSlots; - UpdateField<uint8, 102, 124> NumAccountBankTabs; - UpdateField<UF::ResearchHistory, 102, 125> ResearchHistory; - UpdateField<WorldPackets::PerksProgram::PerksVendorItem, 102, 126> FrozenPerksVendorItem; - UpdateField<UF::ActivePlayerUnk901, 102, 128> Field_1410; - OptionalUpdateField<UF::QuestSession, 102, 127> QuestSession; - UpdateField<int32, 102, 129> UiChromieTimeExpansionID; - UpdateField<int32, 102, 130> TimerunningSeasonID; - UpdateField<int32, 102, 131> TransportServerTime; - UpdateField<uint32, 102, 132> WeeklyRewardsPeriodSinceOrigin; // week count since Cfg_RegionsEntry::ChallengeOrigin - UpdateField<int16, 102, 133> DEBUGSoulbindConduitRank; - UpdateField<WorldPackets::MythicPlus::DungeonScoreData, 134, 135> DungeonScore; - UpdateField<uint32, 134, 136> ActiveCombatTraitConfigID; - UpdateField<int32, 134, 137> ItemUpgradeHighOnehandWeaponItemID; - UpdateField<int32, 134, 138> ItemUpgradeHighFingerItemID; - UpdateField<float, 134, 139> ItemUpgradeHighFingerWatermark; - UpdateField<int32, 134, 140> ItemUpgradeHighTrinketItemID; - UpdateField<float, 134, 141> ItemUpgradeHighTrinketWatermark; - UpdateField<uint64, 134, 142> LootHistoryInstanceID; - OptionalUpdateField<UF::StableInfo, 134, 143> PetStable; - UpdateField<uint8, 134, 144> RequiredMountCapabilityFlags; - OptionalUpdateField<UF::WalkInData, 134, 145> WalkInData; - OptionalUpdateField<UF::DelveData, 134, 146> DelveData; - UpdateFieldArray<ObjectGuid, 232, 147, 148> InvSlots; - UpdateFieldArray<UF::RestInfo, 2, 380, 381> RestInfo; - UpdateFieldArray<int32, 7, 383, 384> ModDamageDonePos; - UpdateFieldArray<int32, 7, 383, 391> ModDamageDoneNeg; - UpdateFieldArray<float, 7, 383, 398> ModDamageDonePercent; - UpdateFieldArray<float, 7, 383, 405> ModHealingDonePercent; - UpdateFieldArray<float, 3, 412, 413> WeaponDmgMultipliers; - UpdateFieldArray<float, 3, 412, 416> WeaponAtkSpeedMultipliers; - UpdateFieldArray<uint32, 12, 419, 420> BuybackPrice; - UpdateFieldArray<int64, 12, 419, 432> BuybackTimestamp; - UpdateFieldArray<int32, 32, 444, 445> CombatRatings; - UpdateFieldArray<uint32, 4, 477, 478> NoReagentCostMask; - UpdateFieldArray<int32, 2, 482, 483> ProfessionSkillLine; - UpdateFieldArray<uint32, 5, 485, 486> BagSlotFlags; - UpdateFieldArray<uint32, 7, 491, 492> BankBagSlotFlags; - UpdateFieldArray<float, 17, 499, 500> ItemUpgradeHighWatermark; + DynamicUpdateField<UF::BankTabSettings, 32, 41> CharacterBankTabSettings; + DynamicUpdateField<UF::BankTabSettings, 32, 42> AccountBankTabSettings; + UpdateField<ObjectGuid, 32, 49> FarsightObject; + UpdateField<ObjectGuid, 32, 50> SummonedBattlePetGUID; + UpdateField<uint64, 32, 51> Coinage; + UpdateField<uint64, 32, 52> AccountBankCoinage; + UpdateField<int32, 32, 53> XP; + UpdateField<int32, 32, 54> NextLevelXP; + UpdateField<int32, 32, 55> TrialXP; + UpdateField<UF::SkillInfo, 32, 56> Skill; + UpdateField<int32, 32, 57> CharacterPoints; + UpdateField<int32, 32, 58> MaxTalentTiers; + UpdateField<uint32, 32, 59> TrackCreatureMask; + UpdateField<float, 32, 60> MainhandExpertise; + UpdateField<float, 32, 61> OffhandExpertise; + UpdateField<float, 32, 62> RangedExpertise; + UpdateField<float, 32, 63> CombatRatingExpertise; + UpdateField<float, 32, 64> BlockPercentage; + UpdateField<float, 32, 65> DodgePercentage; + UpdateField<float, 32, 66> DodgePercentageFromAttribute; + UpdateField<float, 32, 67> ParryPercentage; + UpdateField<float, 32, 68> ParryPercentageFromAttribute; + UpdateField<float, 32, 69> CritPercentage; + UpdateField<float, 70, 71> RangedCritPercentage; + UpdateField<float, 70, 72> OffhandCritPercentage; + UpdateField<float, 70, 73> SpellCritPercentage; + UpdateField<int32, 70, 74> ShieldBlock; + UpdateField<float, 70, 75> ShieldBlockCritPercentage; + UpdateField<float, 70, 76> Mastery; + UpdateField<float, 70, 77> Speed; + UpdateField<float, 70, 78> Avoidance; + UpdateField<float, 70, 79> Sturdiness; + UpdateField<int32, 70, 80> Versatility; + UpdateField<float, 70, 81> VersatilityBonus; + UpdateField<float, 70, 82> PvpPowerDamage; + UpdateField<float, 70, 83> PvpPowerHealing; + UpdateField<UF::BitVectors, 70, 84> BitVectors; + UpdateField<int32, 70, 85> ModHealingDonePos; + UpdateField<float, 70, 86> ModHealingPercent; + UpdateField<float, 70, 87> ModPeriodicHealingDonePercent; + UpdateField<float, 70, 88> ModSpellPowerPercent; + UpdateField<float, 70, 89> ModResiliencePercent; + UpdateField<float, 70, 90> OverrideSpellPowerByAPPercent; + UpdateField<float, 70, 91> OverrideAPBySpellPowerPercent; + UpdateField<int32, 70, 92> ModTargetResistance; + UpdateField<int32, 70, 93> ModTargetPhysicalResistance; + UpdateField<uint32, 70, 94> LocalFlags; + UpdateField<uint8, 70, 95> GrantableLevels; + UpdateField<uint8, 70, 96> MultiActionBars; + UpdateField<uint8, 70, 97> LifetimeMaxRank; + UpdateField<uint8, 70, 98> NumRespecs; + UpdateField<uint32, 70, 99> PvpMedals; + UpdateField<uint16, 70, 100> TodayHonorableKills; + UpdateField<uint16, 70, 101> YesterdayHonorableKills; + UpdateField<uint32, 102, 103> LifetimeHonorableKills; + UpdateField<int32, 102, 104> WatchedFactionIndex; + UpdateField<int32, 102, 105> MaxLevel; + UpdateField<int32, 102, 106> ScalingPlayerLevelDelta; + UpdateField<int32, 102, 107> MaxCreatureScalingLevel; + UpdateField<int32, 102, 108> PetSpellPower; + UpdateField<float, 102, 109> UiHitModifier; + UpdateField<float, 102, 110> UiSpellHitModifier; + UpdateField<int32, 102, 111> HomeRealmTimeOffset; + UpdateField<float, 102, 112> ModPetHaste; + UpdateField<int8, 102, 113> JailersTowerLevelMax; + UpdateField<int8, 102, 114> JailersTowerLevel; + UpdateField<uint8, 102, 115> LocalRegenFlags; + UpdateField<uint8, 102, 116> AuraVision; + UpdateField<uint8, 102, 117> NumBackpackSlots; + UpdateField<int32, 102, 118> OverrideSpellsID; + UpdateField<uint16, 102, 119> LootSpecID; + UpdateField<uint32, 102, 120> OverrideZonePVPType; + UpdateField<int32, 102, 121> Honor; + UpdateField<int32, 102, 122> HonorNextLevel; + UpdateField<int32, 102, 123> PerksProgramCurrency; + UpdateField<uint8, 102, 124> NumBankSlots; + UpdateField<uint8, 102, 125> NumCharacterBankTabs; + UpdateField<uint8, 102, 126> NumAccountBankTabs; + UpdateField<UF::ResearchHistory, 102, 127> ResearchHistory; + UpdateField<WorldPackets::PerksProgram::PerksVendorItem, 102, 128> FrozenPerksVendorItem; + UpdateField<UF::ActivePlayerUnk901, 102, 130> Field_1410; + OptionalUpdateField<UF::QuestSession, 102, 129> QuestSession; + UpdateField<int32, 102, 131> UiChromieTimeExpansionID; + UpdateField<int32, 102, 132> TimerunningSeasonID; + UpdateField<int32, 102, 133> TransportServerTime; + UpdateField<uint32, 134, 135> WeeklyRewardsPeriodSinceOrigin; // week count since Cfg_RegionsEntry::ChallengeOrigin + UpdateField<int16, 134, 136> DEBUGSoulbindConduitRank; + UpdateField<WorldPackets::MythicPlus::DungeonScoreData, 134, 137> DungeonScore; + UpdateField<uint32, 134, 138> ActiveCombatTraitConfigID; + UpdateField<int32, 134, 139> ItemUpgradeHighOnehandWeaponItemID; + UpdateField<int32, 134, 140> ItemUpgradeHighFingerItemID; + UpdateField<float, 134, 141> ItemUpgradeHighFingerWatermark; + UpdateField<int32, 134, 142> ItemUpgradeHighTrinketItemID; + UpdateField<float, 134, 143> ItemUpgradeHighTrinketWatermark; + UpdateField<uint64, 134, 144> LootHistoryInstanceID; + OptionalUpdateField<UF::StableInfo, 134, 145> PetStable; + UpdateField<uint8, 134, 146> RequiredMountCapabilityFlags; + OptionalUpdateField<UF::WalkInData, 134, 147> WalkInData; + OptionalUpdateField<UF::DelveData, 134, 148> DelveData; + OptionalUpdateField<UF::ChallengeModeData, 134, 149> ChallengeModeData; + UpdateFieldArray<ObjectGuid, 105, 150, 151> InvSlots; + UpdateFieldArray<UF::RestInfo, 2, 256, 257> RestInfo; + UpdateFieldArray<int32, 7, 259, 260> ModDamageDonePos; + UpdateFieldArray<int32, 7, 259, 267> ModDamageDoneNeg; + UpdateFieldArray<float, 7, 259, 274> ModDamageDonePercent; + UpdateFieldArray<float, 7, 259, 281> ModHealingDonePercent; + UpdateFieldArray<float, 3, 288, 289> WeaponDmgMultipliers; + UpdateFieldArray<float, 3, 288, 292> WeaponAtkSpeedMultipliers; + UpdateFieldArray<uint32, 12, 295, 296> BuybackPrice; + UpdateFieldArray<int64, 12, 295, 308> BuybackTimestamp; + UpdateFieldArray<int32, 32, 320, 321> CombatRatings; + UpdateFieldArray<uint32, 4, 353, 354> NoReagentCostMask; + UpdateFieldArray<int32, 2, 358, 359> ProfessionSkillLine; + UpdateFieldArray<uint32, 5, 361, 362> BagSlotFlags; + UpdateFieldArray<float, 17, 367, 368> ItemUpgradeHighWatermark; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; @@ -1199,7 +1255,22 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas void ClearChangesMask(); }; -struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<25> +struct GameObjectAssistActionData : public IsUpdateFieldStructureTag +{ + std::string PlayerName; + std::string MonsterName; + uint32 VirtualRealmAddress; + uint8 Sex; + int64 Time; + int32 DelveTier; + + void WriteCreate(ByteBuffer& data, GameObject const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, GameObject const* owner, Player const* receiver) const; + bool operator==(GameObjectAssistActionData const& right) const; + bool operator!=(GameObjectAssistActionData const& right) const { return !(*this == right); } +}; + +struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<26> { UpdateField<std::vector<uint32>, 0, 1> StateWorldEffectIDs; struct StateWorldEffectIDsTag : ViewerDependentValueTag<std::vector<uint32>> {}; @@ -1232,6 +1303,7 @@ struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask< UpdateField<uint32, 0, 22> UiWidgetItemID; UpdateField<uint32, 0, 23> UiWidgetItemQuality; UpdateField<uint32, 0, 24> UiWidgetItemUnknown1000; + OptionalUpdateField<UF::GameObjectAssistActionData, 0, 25> AssistActionData; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const; @@ -1300,33 +1372,163 @@ struct VisualAnim : public IsUpdateFieldStructureTag, public HasChangesMask<5> void ClearChangesMask(); }; -struct AreaTriggerData : public IsUpdateFieldStructureTag, public HasChangesMask<26> -{ - UpdateField<bool, 0, 1> HeightIgnoresScale; - UpdateField<bool, 0, 2> Field_261; - UpdateField<UF::ScaleCurve, 0, 3> OverrideScaleCurve; - UpdateField<UF::ScaleCurve, 0, 4> ExtraScaleCurve; - UpdateField<UF::ScaleCurve, 0, 5> OverrideMoveCurveX; - UpdateField<UF::ScaleCurve, 0, 6> OverrideMoveCurveY; - UpdateField<UF::ScaleCurve, 0, 7> OverrideMoveCurveZ; - UpdateField<ObjectGuid, 0, 8> Caster; - UpdateField<uint32, 0, 9> Duration; - UpdateField<uint32, 0, 10> TimeToTarget; - UpdateField<uint32, 0, 11> TimeToTargetScale; - UpdateField<uint32, 0, 12> TimeToTargetExtraScale; - UpdateField<uint32, 0, 13> TimeToTargetPos; // Linked to m_overrideMoveCurve - UpdateField<int32, 0, 14> SpellID; - UpdateField<int32, 0, 15> SpellForVisuals; - UpdateField<UF::SpellCastVisual, 0, 16> SpellVisual; - UpdateField<float, 0, 17> BoundsRadius2D; - UpdateField<uint32, 0, 18> DecalPropertiesID; - UpdateField<ObjectGuid, 0, 19> CreatingEffectGUID; - UpdateField<uint32, 0, 20> NumUnitsInside; - UpdateField<uint32, 0, 21> NumPlayersInside; // When not 0 this causes SpellVisualEvent 14 to trigger, playing alternate visuals, typically used by "SOAK THIS" areatriggers - UpdateField<ObjectGuid, 0, 22> OrbitPathTarget; - UpdateField<TaggedPosition<Position::XYZ>, 0, 23> RollPitchYaw; - UpdateField<int32, 0, 24> PositionalSoundKitID; - UpdateField<UF::VisualAnim, 0, 25> VisualAnim; +struct ForceSetAreaTriggerPositionAndRotation : public IsUpdateFieldStructureTag +{ + ObjectGuid TriggerGUID; + TaggedPosition<::Position::XYZ> Position; + QuaternionData Rotation; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + bool operator==(ForceSetAreaTriggerPositionAndRotation const& right) const; + bool operator!=(ForceSetAreaTriggerPositionAndRotation const& right) const { return !(*this == right); } +}; + +struct AreaTriggerSplineCalculator : public IsUpdateFieldStructureTag, public HasChangesMask<3> +{ + UpdateField<bool, 0, 1> Catmullrom; + DynamicUpdateField<TaggedPosition<Position::XYZ>, 0, 2> Points; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerOrbit : public IsUpdateFieldStructureTag, public HasChangesMask<7> +{ + UpdateField<bool, 0, 1> CounterClockwise; + UpdateField<TaggedPosition<Position::XYZ>, 0, 2> Center; + UpdateField<float, 0, 3> Radius; + UpdateField<float, 0, 4> InitialAngle; + UpdateField<float, 0, 5> BlendFromRadius; + UpdateField<int32, 0, 6> ExtraTimeForBlending; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerMovementScript : public IsUpdateFieldStructureTag, public HasChangesMask<4> +{ + UpdateField<int32, 0, 1> SpellScriptID; + UpdateField<TaggedPosition<Position::XYZ>, 0, 2> Center; + UpdateField<uint32, 0, 3> CreationTime; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerSphere : public IsUpdateFieldStructureTag, public HasChangesMask<3> +{ + UpdateField<float, 0, 1> Radius; + UpdateField<float, 0, 2> RadiusTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerBox : public IsUpdateFieldStructureTag, public HasChangesMask<3> +{ + UpdateField<TaggedPosition<Position::XYZ>, 0, 1> Extents; + UpdateField<TaggedPosition<Position::XYZ>, 0, 2> ExtentsTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerPolygon : public IsUpdateFieldStructureTag, public HasChangesMask<5> +{ + DynamicUpdateField<TaggedPosition<Position::XY>, 0, 1> Vertices; + DynamicUpdateField<TaggedPosition<Position::XY>, 0, 2> VerticesTarget; + UpdateField<float, 0, 3> Height; + UpdateField<float, 0, 4> HeightTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerCylinder : public IsUpdateFieldStructureTag, public HasChangesMask<7> +{ + UpdateField<float, 0, 1> Radius; + UpdateField<float, 0, 2> RadiusTarget; + UpdateField<float, 0, 3> Height; + UpdateField<float, 0, 4> HeightTarget; + UpdateField<float, 0, 5> LocationZOffset; + UpdateField<float, 0, 6> LocationZOffsetTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerDisk : public IsUpdateFieldStructureTag, public HasChangesMask<9> +{ + UpdateField<float, 0, 1> InnerRadius; + UpdateField<float, 0, 2> InnerRadiusTarget; + UpdateField<float, 0, 3> OuterRadius; + UpdateField<float, 0, 4> OuterRadiusTarget; + UpdateField<float, 0, 5> Height; + UpdateField<float, 0, 6> HeightTarget; + UpdateField<float, 0, 7> LocationZOffset; + UpdateField<float, 0, 8> LocationZOffsetTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerBoundedPlane : public IsUpdateFieldStructureTag, public HasChangesMask<3> +{ + UpdateField<TaggedPosition<Position::XY>, 0, 1> Extents; + UpdateField<TaggedPosition<Position::XY>, 0, 2> ExtentsTarget; + + void WriteCreate(ByteBuffer& data, AreaTrigger const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, AreaTrigger const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct AreaTriggerData : public IsUpdateFieldStructureTag, public HasChangesMask<36> +{ + UpdateField<UF::ScaleCurve, 0, 1> OverrideScaleCurve; + UpdateField<UF::ScaleCurve, 0, 2> ExtraScaleCurve; + UpdateField<UF::ScaleCurve, 0, 3> OverrideMoveCurveX; + UpdateField<UF::ScaleCurve, 0, 4> OverrideMoveCurveY; + UpdateField<UF::ScaleCurve, 0, 5> OverrideMoveCurveZ; + UpdateField<ObjectGuid, 0, 6> Caster; + UpdateField<uint32, 0, 7> Duration; + UpdateField<uint32, 0, 8> TimeToTarget; + UpdateField<uint32, 0, 9> TimeToTargetScale; + UpdateField<uint32, 0, 10> TimeToTargetExtraScale; + UpdateField<uint32, 0, 11> TimeToTargetPos; // Linked to m_overrideMoveCurve + UpdateField<int32, 0, 12> SpellID; + UpdateField<int32, 0, 13> SpellForVisuals; + UpdateField<UF::SpellCastVisual, 0, 14> SpellVisual; + UpdateField<float, 0, 15> BoundsRadius2D; + UpdateField<uint32, 0, 16> DecalPropertiesID; + UpdateField<ObjectGuid, 0, 17> CreatingEffectGUID; + UpdateField<ObjectGuid, 0, 18> OrbitPathTarget; + UpdateField<TaggedPosition<Position::XYZ>, 0, 19> RollPitchYaw; + UpdateField<int32, 0, 20> PositionalSoundKitID; + UpdateField<uint32, 0, 21> MovementStartTime; + UpdateField<uint32, 0, 22> CreationTime; + UpdateField<float, 0, 23> ZOffset; + OptionalUpdateField<TaggedPosition<Position::XYZ>, 0, 24> TargetRollPitchYaw; + UpdateField<uint32, 0, 25> Flags; + UpdateField<UF::VisualAnim, 0, 26> VisualAnim; + UpdateField<uint32, 0, 27> ScaleCurveId; + UpdateField<uint32, 0, 28> FacingCurveId; + UpdateField<uint32, 0, 29> MorphCurveId; + UpdateField<uint32, 0, 30> MoveCurveId; + UpdateField<float, 0, 31> Facing; + OptionalUpdateField<UF::ForceSetAreaTriggerPositionAndRotation, 32, 33> ForcedPositionAndRotation; + UpdateField<int32, 32, 34> PathType; + UpdateField<uint8, 32, 35> ShapeType; + VariantUpdateField<32, 34, UF::AreaTriggerSplineCalculator, UF::AreaTriggerOrbit, UF::AreaTriggerMovementScript> PathData; + VariantUpdateField<32, 35, UF::AreaTriggerSphere, UF::AreaTriggerBox, UF::AreaTriggerPolygon, UF::AreaTriggerCylinder, UF::AreaTriggerDisk, UF::AreaTriggerBoundedPlane> ShapeData; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3ac1815f4f6..1d28e4f8aac 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -337,8 +337,6 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) healthBeforeDuel = 0; manaBeforeDuel = 0; - memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*)); - _cinematicMgr = std::make_unique<CinematicMgr>(this); m_achievementMgr = std::make_unique<PlayerAchievementMgr>(this); @@ -374,9 +372,6 @@ Player::~Player() for (ItemSetEffect* itemSetEff : ItemSetEff) DeleteItemSetEffects(itemSetEff); - for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) - delete _voidStorageItems[i]; - sWorld->DecreasePlayerCount(); } @@ -3719,21 +3714,9 @@ void Player::DestroyForPlayer(Player* target) const if (target == this) { - for (uint8 i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->DestroyForPlayer(target); - } - - for (uint8 i = REAGENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->DestroyForPlayer(target); - } + for (Item* item : m_items) + if (item) + item->DestroyForPlayer(target); } } @@ -4195,10 +4178,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_CHAR_GUID); - stmt->setUInt64(0, guid); - trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_FISHINGSTEPS); stmt->setUInt64(0, guid); trans->Append(stmt); @@ -4233,6 +4212,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_DATA_ELEMENTS_CHARACTER_BY_GUID); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_DATA_FLAGS_CHARACTER_BY_GUID); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BANK_TAB_SETTINGS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + sCharacterCache->DeleteCharacterCacheEntry(playerguid, name); break; } @@ -9488,10 +9479,6 @@ uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location / if (location.HasFlag(ItemSearchLocation::Bank)) { - for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i) - if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - ++freeSlotCount; - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) if (Bag* bag = GetBagByPos(i)) for (uint32 j = 0; j < GetBagSize(bag); ++j) @@ -9506,10 +9493,6 @@ uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location / for (uint32 j = 0; j < GetBagSize(bag); ++j) if (!GetItemInBag(bag, j)) ++freeSlotCount; - - for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) - if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - ++freeSlotCount; } return freeSlotCount; @@ -9759,21 +9742,10 @@ bool Player::IsEquipmentPos(uint8 bag, uint8 slot) bool Player::IsBankPos(uint8 bag, uint8 slot) { - if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END)) - return true; if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)) return true; if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END) return true; - if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END)) - return true; - return false; -} - -bool Player::IsReagentBankPos(uint8 bag, uint8 slot) -{ - if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END)) - return true; return false; } @@ -9795,6 +9767,13 @@ bool Player::IsChildEquipmentPos(uint8 bag, uint8 slot) return bag == INVENTORY_SLOT_BAG_0 && (slot >= CHILD_EQUIPMENT_SLOT_START && slot < CHILD_EQUIPMENT_SLOT_END); } +bool Player::IsAccountBankPos(uint8 bag, uint8 /*slot*/) +{ + if (bag >= ACCOUNT_BANK_SLOT_BAG_START && bag < ACCOUNT_BANK_SLOT_BAG_END) + return true; + return false; +} + bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const { // post selected @@ -9827,18 +9806,10 @@ bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const if (slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_START + GetInventorySlotCount()) return true; - // bank main slots - if (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END) - return true; - // bank bag slots if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) return true; - // reagent bank bag slots - if (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END) - return true; - return false; } @@ -10126,10 +10097,6 @@ InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemP // prevent cheating if ((slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) || slot >= PLAYER_SLOT_END) return EQUIP_ERR_WRONG_BAG_TYPE; - - // can't store anything else than crafting reagents in Reagent Bank - if (IsReagentBankPos(bag, slot) && (!IsReagentBankUnlocked() || !pProto->IsCraftingReagent())) - return EQUIP_ERR_WRONG_BAG_TYPE; } else { @@ -11072,12 +11039,6 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest ASSERT(bag == NULL_BAG && slot == NULL_SLOT); // when reagentBankOnly is true then bag & slot must be hardcoded constants, not client input } - if ((IsReagentBankPos(bag, slot) || reagentBankOnly) && !IsReagentBankUnlocked()) - return EQUIP_ERR_REAGENT_BANK_LOCKED; - - uint8 slotStart = reagentBankOnly ? uint8(REAGENT_SLOT_START) : uint8(BANK_SLOT_ITEM_START); - uint8 slotEnd = reagentBankOnly ? uint8(REAGENT_SLOT_END) : uint8(BANK_SLOT_ITEM_END); - uint32 count = pItem->GetCount(); TC_LOG_DEBUG("entities.player.items", "Player::CanBankItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}, Count: {}", @@ -11114,7 +11075,7 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest if (!pItem->IsBag()) return EQUIP_ERR_WRONG_SLOT; - if (slot - BANK_SLOT_BAG_START >= GetBankBagSlotCount()) + if (slot - BANK_SLOT_BAG_START >= GetCharacterBankTabCount()) return EQUIP_ERR_NO_BANK_SLOT; res = CanUseItem(pItem, not_loading); @@ -11143,12 +11104,7 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest { if (bag == INVENTORY_SLOT_BAG_0) { - res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - return res; - - if (count == 0) - return EQUIP_ERR_OK; + return EQUIP_ERR_WRONG_SLOT; // TODO: check if INVENTORY_SLOT_BAG_0 condition is neccessary } else { @@ -11167,12 +11123,7 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest // search free slot in bag if (bag == INVENTORY_SLOT_BAG_0) { - res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - return res; - - if (count == 0) - return EQUIP_ERR_OK; + return EQUIP_ERR_WRONG_SLOT; // TODO: check if INVENTORY_SLOT_BAG_0 condition is neccessary } else { @@ -11193,50 +11144,14 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest // search stack for merge to if (pProto->GetMaxStackSize() != 1) { - // in slots - res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - return res; - - if (count == 0) - return EQUIP_ERR_OK; - - // don't try to store reagents anywhere else than in Reagent Bank if we're on it - if (!reagentBankOnly) - { - // in special bags - if (pProto->GetBagFamily()) - { - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - continue; - - if (count == 0) - return EQUIP_ERR_OK; - } - } - - // in regular bags - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - continue; - - if (count == 0) - return EQUIP_ERR_OK; - } - } - } - - // search free space in special bags (don't try to store reagents anywhere else than in Reagent Bank if we're on it) - if (!reagentBankOnly && pProto->GetBagFamily()) - { + // in regular bags for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { - res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot); + // only consider tabs marked as reagents if requested + if (reagentBankOnly && !(*m_activePlayerData->CharacterBankTabSettings[i - BANK_SLOT_BAG_START].DepositFlags & AsUnderlyingType(BagSlotFlags::PriorityReagents))) + continue; + + res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot); if (res != EQUIP_ERR_OK) continue; @@ -11245,26 +11160,19 @@ InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest } } - // search free space - res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, false, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - return res; - - if (count == 0) - return EQUIP_ERR_OK; - - // search free space in regular bags (don't try to store reagents anywhere else than in Reagent Bank if we're on it) - if (!reagentBankOnly) + // search free space in regular bags + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) - { - res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot); - if (res != EQUIP_ERR_OK) - continue; + // only consider tabs marked as reagents if requested + if (reagentBankOnly && !(*m_activePlayerData->CharacterBankTabSettings[i - BANK_SLOT_BAG_START].DepositFlags & AsUnderlyingType(BagSlotFlags::PriorityReagents))) + continue; - if (count == 0) - return EQUIP_ERR_OK; - } + res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot); + if (res != EQUIP_ERR_OK) + continue; + + if (count == 0) + return EQUIP_ERR_OK; } return reagentBankOnly ? EQUIP_ERR_REAGENT_BANK_FULL : EQUIP_ERR_BANK_FULL; @@ -12272,33 +12180,6 @@ uint32 Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, boo } } - // in bank - for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) - { - if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - { - if (item->GetEntry() == itemEntry && !item->IsInTrade()) - { - if (item->GetCount() + remcount <= count) - { - remcount += item->GetCount(); - DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - if (remcount >= count) - return remcount; - } - else - { - item->SetCount(item->GetCount() - count + remcount); - ItemRemovedQuestCheck(item->GetEntry(), count - remcount); - if (IsInWorld() && update) - item->SendUpdateToPlayer(this); - item->SetState(ITEM_CHANGED, this); - return count; - } - } - } - } - // in bank bags for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { @@ -12364,34 +12245,6 @@ uint32 Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, boo } } - for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) - { - if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - { - if (item->GetEntry() == itemEntry && !item->IsInTrade()) - { - if (item->GetCount() + remcount <= count) - { - // all keys can be unequipped - remcount += item->GetCount(); - DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - - if (remcount >= count) - return remcount; - } - else - { - item->SetCount(item->GetCount() - count + remcount); - ItemRemovedQuestCheck(item->GetEntry(), count - remcount); - if (IsInWorld() && update) - item->SendUpdateToPlayer(this); - item->SetState(ITEM_CHANGED, this); - return count; - } - } - } - } - for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) { if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) @@ -12746,12 +12599,6 @@ void Player::SwapItem(uint16 src, uint16 dst) } } - if (IsReagentBankPos(dst) && !IsReagentBankUnlocked()) - { - SendEquipError(EQUIP_ERR_REAGENT_BANK_LOCKED, pSrcItem, pDstItem); - return; - } - // NOW this is or item move (swap with empty), or swap with another item (including bags in bag possitions) // or swap empty bag with another empty or not empty bag (with items exchange) @@ -12785,8 +12632,7 @@ void Player::SwapItem(uint16 src, uint16 dst) RemoveItem(srcbag, srcslot, true); BankItem(dest, pSrcItem, true); - if (!IsReagentBankPos(dst)) - ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount()); + ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount()); } else if (IsEquipmentPos(dst)) { @@ -17819,7 +17665,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol struct PlayerLoadData { // "SELECT c.guid, account, name, race, class, gender, level, xp, money, inventorySlots, inventoryBagFlags, bagSlotFlags1, bagSlotFlags2, bagSlotFlags3, bagSlotFlags4, bagSlotFlags5, " - // "bankSlots, bankBagFlags, bankBagSlotFlags1, bankBagSlotFlags2, bankBagSlotFlags3, bankBagSlotFlags4, bankBagSlotFlags5, bankBagSlotFlags6, bankBagSlotFlags7, restState, playerFlags, playerFlagsEx, " + // "bankSlots, bankTabs, bankBagFlags, restState, playerFlags, playerFlagsEx, " // "position_x, position_y, position_z, map, orientation, taximask, createTime, createMode, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " // "resettalents_time, primarySpecialization, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, summonedPetNumber, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, " // "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " @@ -17841,8 +17687,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol EnumFlag<BagSlotFlags> inventoryBagFlags = BagSlotFlags::None; std::array<BagSlotFlags, 5> bagSlotFlags; uint8 bankSlots; + uint8 bankTabs; EnumFlag<BagSlotFlags> bankBagFlags = BagSlotFlags::None; - std::array<BagSlotFlags, 7> bankBagSlotFlags; PlayerRestState restState; PlayerFlags playerFlags; PlayerFlagsEx playerFlagsEx; @@ -17921,9 +17767,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol for (BagSlotFlags& flags : bagSlotFlags) flags = static_cast<BagSlotFlags>(fields[i++].GetUInt32()); bankSlots = fields[i++].GetUInt8(); + bankTabs = fields[i++].GetUInt8(); bankBagFlags = static_cast<BagSlotFlags>(fields[i++].GetUInt32()); - for (BagSlotFlags& flags : bankBagSlotFlags) - flags = static_cast<BagSlotFlags>(fields[i++].GetUInt32()); restState = PlayerRestState(fields[i++].GetUInt8()); playerFlags = PlayerFlags(fields[i++].GetUInt32()); playerFlagsEx = PlayerFlagsEx(fields[i++].GetUInt32()); @@ -18083,9 +17928,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol for (uint32 bagIndex = 0; bagIndex < fields.bagSlotFlags.size(); ++bagIndex) ReplaceAllBagSlotFlags(bagIndex, fields.bagSlotFlags[bagIndex]); SetBankBagSlotCount(fields.bankSlots); + SetCharacterBankTabCount(fields.bankTabs); SetBankAutoSortDisabled(fields.bankBagFlags.HasFlag(BagSlotFlags::DisableAutoSort)); - for (uint32 bagIndex = 0; bagIndex < fields.bankBagSlotFlags.size(); ++bagIndex) - ReplaceAllBankBagSlotFlags(bagIndex, fields.bankBagSlotFlags[bagIndex]); SetNativeGender(fields.gender); SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::Inebriation), fields.drunk); ReplaceAllPlayerFlags(fields.playerFlags); @@ -18520,6 +18364,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol // must be before inventory (some items required reputation check) m_reputationMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION)); + _LoadCharacterBankTabSettings(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANK_TAB_SETTINGS)); + _LoadInventory(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AZERITE), @@ -18528,9 +18374,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AZERITE_EMPOWERED), time_diff); - if (IsVoidStorageUnlocked()) - _LoadVoidStorage(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE)); - // update items with duration and realtime UpdateItemDuration(time_diff, true); @@ -19195,63 +19038,6 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti ApplyAllAzeriteItemMods(true); } -void Player::_LoadVoidStorage(PreparedQueryResult result) -{ - if (!result) - return; - - do - { - // SELECT itemId, itemEntry, slot, creatorGuid, randomBonusListId, fixedScalingLevel, artifactKnowledgeLevel, context, bonusListIDs FROM character_void_storage WHERE playerGuid = ? - Field* fields = result->Fetch(); - - uint64 itemId = fields[0].GetUInt64(); - uint32 itemEntry = fields[1].GetUInt32(); - uint8 slot = fields[2].GetUInt8(); - ObjectGuid creatorGuid = fields[3].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt64()) : ObjectGuid::Empty; - ItemRandomBonusListId randomBonusListId = fields[4].GetUInt32(); - uint32 fixedScalingLevel = fields[5].GetUInt32(); - uint32 artifactKnowledgeLevel = fields[6].GetUInt32(); - ItemContext context = ItemContext(fields[7].GetUInt8()); - std::vector<int32> bonusListIDs; - for (std::string_view bonusListIDtoken : Trinity::Tokenize(fields[8].GetStringView(), ' ', false)) - if (Optional<int32> bonusListID = Trinity::StringTo<int32>(bonusListIDtoken)) - bonusListIDs.push_back(*bonusListID); - - if (!itemId) - { - TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid id (item id: {}, entry: {}).", - GetName(), GetGUID().ToString(), itemId, itemEntry); - continue; - } - - if (!sObjectMgr->GetItemTemplate(itemEntry)) - { - TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid entry (item id: {}, entry: {}).", - GetName(), GetGUID().ToString(), itemId, itemEntry); - continue; - } - - if (slot >= VOID_STORAGE_MAX_SLOT) - { - TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid slot (item id: {}, entry: {}, slot: {}).", - GetName(), GetGUID().ToString(), itemId, itemEntry, slot); - continue; - } - - _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomBonusListId, fixedScalingLevel, artifactKnowledgeLevel, - context, bonusListIDs); - - WorldPackets::Item::ItemInstance voidInstance; - voidInstance.Initialize(_voidStorageItems[slot]); - BonusData bonus; - bonus.Initialize(voidInstance); - - GetSession()->GetCollectionMgr()->AddItemAppearance(itemEntry, bonus.AppearanceModID); - } - while (result->NextRow()); -} - Item* Player::_LoadItem(CharacterDatabaseTransaction trans, uint32 zoneId, uint32 timeDiff, Field* fields) { Item* item = nullptr; @@ -20300,6 +20086,27 @@ void Player::_LoadPlayerData(PreparedQueryResult elementsResult, PreparedQueryRe } } +void Player::_LoadCharacterBankTabSettings(PreparedQueryResult result) +{ + if (result) + { + do + { + DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (tabId)(name)(icon)(description)(depositFlags)) fields { *result }; + + if (fields.tabId().GetUInt8() >= (BANK_SLOT_BAG_END - BANK_SLOT_BAG_START)) + continue; + + SetCharacterBankTabSettings(fields.tabId().GetUInt8(), fields.name().GetString(), fields.icon().GetString(), + fields.description().GetString(), static_cast<BagSlotFlags>(fields.depositFlags().GetUInt32())); + + } while (result->NextRow()); + } + + while (m_activePlayerData->CharacterBankTabSettings.size() < *m_activePlayerData->NumCharacterBankTabs) + AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CharacterBankTabSettings)); +} + /*********************************************************/ /*** SAVE SYSTEM ***/ /*********************************************************/ @@ -20372,6 +20179,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba for (uint32 bagSlotFlag : m_activePlayerData->BagSlotFlags) stmt->setUInt32(index++, bagSlotFlag); stmt->setUInt8(index++, GetBankBagSlotCount()); + stmt->setUInt8(index++, GetCharacterBankTabCount()); stmt->setUInt32(index++, [&] { BagSlotFlags inventoryFlags = BagSlotFlags::None; @@ -20379,8 +20187,6 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba inventoryFlags |= BagSlotFlags::DisableAutoSort; return AsUnderlyingType(inventoryFlags); }()); - for (uint32 bankBagSlotFlag : m_activePlayerData->BankBagSlotFlags) - stmt->setUInt32(index++, bankBagSlotFlag); stmt->setUInt8(index++, m_activePlayerData->RestInfo[REST_TYPE_XP].StateID); stmt->setUInt32(index++, m_playerData->PlayerFlags); stmt->setUInt32(index++, m_playerData->PlayerFlagsEx); @@ -20512,6 +20318,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba for (uint32 bagSlotFlag : m_activePlayerData->BagSlotFlags) stmt->setUInt32(index++, bagSlotFlag); stmt->setUInt8(index++, GetBankBagSlotCount()); + stmt->setUInt8(index++, GetCharacterBankTabCount()); stmt->setUInt32(index++, [&] { BagSlotFlags inventoryFlags = BagSlotFlags::None; @@ -20519,8 +20326,6 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba inventoryFlags |= BagSlotFlags::DisableAutoSort; return AsUnderlyingType(inventoryFlags); }()); - for (uint32 bankBagSlotFlag : m_activePlayerData->BankBagSlotFlags) - stmt->setUInt32(index++, bankBagSlotFlag); stmt->setUInt8(index++, m_activePlayerData->RestInfo[REST_TYPE_XP].StateID); stmt->setUInt32(index++, m_playerData->PlayerFlags); stmt->setUInt32(index++, m_playerData->PlayerFlagsEx); @@ -20675,7 +20480,6 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba _SaveCustomizations(trans); _SaveBGData(trans); _SaveInventory(trans); - _SaveVoidStorage(trans); _SaveQuestStatus(trans); _SaveDailyQuestStatus(trans); _SaveWeeklyQuestStatus(trans); @@ -20699,6 +20503,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba _SaveCurrency(trans); _SaveCUFProfiles(trans); _SavePlayerData(trans); + _SaveCharacterBankTabSettings(trans); if (_garrison) _garrison->SaveToDB(trans); @@ -21044,42 +20849,6 @@ void Player::_SaveInventory(CharacterDatabaseTransaction trans) m_itemUpdateQueue.clear(); } -void Player::_SaveVoidStorage(CharacterDatabaseTransaction trans) -{ - CharacterDatabasePreparedStatement* stmt = nullptr; - - for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) - { - if (!_voidStorageItems[i]) // unused item - { - // DELETE FROM void_storage WHERE slot = ? AND playerGuid = ? - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT); - stmt->setUInt8(0, i); - stmt->setUInt64(1, GetGUID().GetCounter()); - } - else - { - // REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomBonusListId, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM); - stmt->setUInt64(0, _voidStorageItems[i]->ItemId); - stmt->setUInt64(1, GetGUID().GetCounter()); - stmt->setUInt32(2, _voidStorageItems[i]->ItemEntry); - stmt->setUInt8(3, i); - stmt->setUInt64(4, _voidStorageItems[i]->CreatorGuid.GetCounter()); - stmt->setUInt32(5, _voidStorageItems[i]->RandomBonusListId); - stmt->setUInt32(6, _voidStorageItems[i]->FixedScalingLevel); - stmt->setUInt32(7, _voidStorageItems[i]->ArtifactKnowledgeLevel); - stmt->setUInt8(8, AsUnderlyingType(_voidStorageItems[i]->Context)); - std::ostringstream bonusListIDs; - for (int32 bonusListID : _voidStorageItems[i]->BonusListIDs) - bonusListIDs << bonusListID << ' '; - stmt->setString(9, bonusListIDs.str()); - } - - trans->Append(stmt); - } -} - void Player::_SaveCUFProfiles(CharacterDatabaseTransaction trans) { CharacterDatabasePreparedStatement* stmt; @@ -21666,6 +21435,26 @@ void Player::_SavePlayerData(CharacterDatabaseTransaction trans) _playerDataFlagsNeedSave.clear(); } +void Player::_SaveCharacterBankTabSettings(CharacterDatabaseTransaction trans) const +{ + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BANK_TAB_SETTINGS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + for (std::size_t i = 0; i < m_activePlayerData->CharacterBankTabSettings.size(); ++i) + { + UF::BankTabSettings const& tabSetting = m_activePlayerData->CharacterBankTabSettings[i]; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_BANK_TAB_SETTINGS); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt8(1, i); + stmt->setString(2, *tabSetting.Name); + stmt->setString(3, *tabSetting.Icon); + stmt->setString(4, *tabSetting.Description); + stmt->setInt32(5, *tabSetting.DepositFlags); + trans->Append(stmt); + } +} + void Player::outDebugValues() const { if (!sLog->ShouldLog("entities.unit", LOG_LEVEL_DEBUG)) @@ -28387,7 +28176,13 @@ void Player::_LoadTraits(PreparedQueryResult configsResult, PreparedQueryResult }); if (activeConfig >= 0) - SetActiveCombatTraitConfigID(m_activePlayerData->TraitConfigs[activeConfig].ID); + { + UF::TraitConfig const& activeTraitConfig = m_activePlayerData->TraitConfigs[activeConfig]; + SetActiveCombatTraitConfigID(activeTraitConfig.ID); + int32 activeSubTree = activeTraitConfig.SubTrees.FindIndexIf([](UF::TraitSubTreeCache const& subTree) { return subTree.Active != 0; }); + if (activeSubTree >= 0) + SetCurrentCombatTraitConfigSubTreeID(activeTraitConfig.SubTrees[activeSubTree].TraitSubTreeID); + } for (UF::TraitConfig const& traitConfig : m_activePlayerData->TraitConfigs) { @@ -28657,9 +28452,20 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) && (static_cast<TraitCombatConfigFlags>(*traitConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) != TraitCombatConfigFlags::None; }); if (specTraitConfigIndex >= 0) - SetActiveCombatTraitConfigID(m_activePlayerData->TraitConfigs[specTraitConfigIndex].ID); + { + UF::TraitConfig const& activeTraitConfig = m_activePlayerData->TraitConfigs[specTraitConfigIndex]; + SetActiveCombatTraitConfigID(activeTraitConfig.ID); + int32 activeSubTree = activeTraitConfig.SubTrees.FindIndexIf([](UF::TraitSubTreeCache const& subTree) { return subTree.Active != 0; }); + if (activeSubTree >= 0) + SetCurrentCombatTraitConfigSubTreeID(activeTraitConfig.SubTrees[activeSubTree].TraitSubTreeID); + else + SetCurrentCombatTraitConfigSubTreeID(0); + } else + { SetActiveCombatTraitConfigID(0); + SetCurrentCombatTraitConfigSubTreeID(0); + } for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { @@ -29097,6 +28903,17 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: } } + if (applyTraits) + { + int32 activeSubTree = editedConfig.SubTrees.FindIndexIf([](UF::TraitSubTreeCache const& subTree) { return subTree.Active != 0; }); + if (activeSubTree >= 0) + SetCurrentCombatTraitConfigSubTreeID(editedConfig.SubTrees[activeSubTree].TraitSubTreeID); + else + SetCurrentCombatTraitConfigSubTreeID(0); + + UpdateItemSetAuras(this, false); + } + m_traitConfigStates[editedConfigId] = PLAYERSPELL_CHANGED; } @@ -29856,86 +29673,6 @@ bool Player::IsInWhisperWhiteList(ObjectGuid guid) return false; } -uint8 Player::GetNextVoidStorageFreeSlot() const -{ - for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) - if (!_voidStorageItems[i]) // unused item - return i; - - return VOID_STORAGE_MAX_SLOT; -} - -uint8 Player::GetNumOfVoidStorageFreeSlots() const -{ - uint8 count = 0; - - for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) - if (!_voidStorageItems[i]) - count++; - - return count; -} - -uint8 Player::AddVoidStorageItem(VoidStorageItem&& item) -{ - uint8 slot = GetNextVoidStorageFreeSlot(); - - if (slot >= VOID_STORAGE_MAX_SLOT) - { - GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); - return 255; - } - - _voidStorageItems[slot] = new VoidStorageItem(std::move(item)); - return slot; -} - -void Player::DeleteVoidStorageItem(uint8 slot) -{ - if (slot >= VOID_STORAGE_MAX_SLOT) - { - GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); - return; - } - - delete _voidStorageItems[slot]; - _voidStorageItems[slot] = nullptr; -} - -bool Player::SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot) -{ - if (oldSlot >= VOID_STORAGE_MAX_SLOT || newSlot >= VOID_STORAGE_MAX_SLOT || oldSlot == newSlot) - return false; - - std::swap(_voidStorageItems[newSlot], _voidStorageItems[oldSlot]); - return true; -} - -VoidStorageItem* Player::GetVoidStorageItem(uint8 slot) const -{ - if (slot >= VOID_STORAGE_MAX_SLOT) - { - GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); - return nullptr; - } - - return _voidStorageItems[slot]; -} - -VoidStorageItem* Player::GetVoidStorageItem(uint64 id, uint8& slot) const -{ - for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) - { - if (_voidStorageItems[i] && _voidStorageItems[i]->ItemId == id) - { - slot = i; - return _voidStorageItems[i]; - } - } - - return nullptr; -} - void Player::CreateGarrison(uint32 garrSiteId) { std::unique_ptr<Garrison> garrison(new Garrison(this)); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2a51422b9a7..2a28c516dc0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -511,21 +511,24 @@ DEFINE_ENUM_FLAG(PlayerFlagsEx); enum PlayerLocalFlags { - PLAYER_LOCAL_FLAG_CONTROLLING_PET = 0x00000001, // Displays "You have an active summon already" when trying to tame new pet - PLAYER_LOCAL_FLAG_TRACK_STEALTHED = 0x00000002, - PLAYER_LOCAL_FLAG_RELEASE_TIMER = 0x00000008, // Display time till auto release spirit - PLAYER_LOCAL_FLAG_NO_RELEASE_WINDOW = 0x00000010, // Display no "release spirit" window at all - PLAYER_LOCAL_FLAG_NO_PET_BAR = 0x00000020, // CGPetInfo::IsPetBarUsed - PLAYER_LOCAL_FLAG_OVERRIDE_CAMERA_MIN_HEIGHT = 0x00000040, - PLAYER_LOCAL_FLAG_NEWLY_BOOSTED_CHARACTER = 0x00000080, - PLAYER_LOCAL_FLAG_USING_PARTY_GARRISON = 0x00000100, - PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED = 0x00000200, - PLAYER_LOCAL_FLAG_CAN_VISIT_PARTY_GARRISON = 0x00000400, - PLAYER_LOCAL_FLAG_WAR_MODE = 0x00000800, - PLAYER_LOCAL_FLAG_ACCOUNT_SECURED = 0x00001000, // Script_IsAccountSecured - PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME= 0x00008000, - PLAYER_LOCAL_FLAG_MENTOR_RESTRICTED = 0x00020000, - PLAYER_LOCAL_FLAG_WEEKLY_REWARD_AVAILABLE = 0x00040000, + PLAYER_LOCAL_FLAG_CONTROLLING_PET = 0x00000001, // Displays "You have an active summon already" when trying to tame new pet + PLAYER_LOCAL_FLAG_TRACK_STEALTHED = 0x00000002, + PLAYER_LOCAL_FLAG_RELEASE_TIMER = 0x00000008, // Display time till auto release spirit + PLAYER_LOCAL_FLAG_NO_RELEASE_WINDOW = 0x00000010, // Display no "release spirit" window at all + PLAYER_LOCAL_FLAG_NO_PET_BAR = 0x00000020, // CGPetInfo::IsPetBarUsed + PLAYER_LOCAL_FLAG_OVERRIDE_CAMERA_MIN_HEIGHT = 0x00000040, + PLAYER_LOCAL_FLAG_NEWLY_BOOSTED_CHARACTER = 0x00000080, + PLAYER_LOCAL_FLAG_USING_PARTY_GARRISON = 0x00000100, + PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED = 0x00000200, + PLAYER_LOCAL_FLAG_CAN_VISIT_PARTY_GARRISON = 0x00000400, + PLAYER_LOCAL_FLAG_WAR_MODE = 0x00000800, + PLAYER_LOCAL_FLAG_ACCOUNT_SECURED = 0x00001000, // Script_IsAccountSecured + PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME = 0x00008000, + PLAYER_LOCAL_FLAG_MENTOR_RESTRICTED = 0x00020000, + PLAYER_LOCAL_FLAG_HAS_ACCOUNT_BANK_LOCK = 0x00040000, + PLAYER_LOCAL_FLAG_CHARACTER_BANK_DISABLED = 0x00080000, + PLAYER_LOCAL_FLAG_CHARACTER_BANK_CONVERSION_FAILED = 0x00100000, + PLAYER_LOCAL_FLAG_ACCOUNT_BANK_DISABLED = 0x00200000, }; DEFINE_ENUM_FLAG(PlayerLocalFlags); @@ -642,7 +645,6 @@ typedef std::unordered_map<uint32, SkillStatusData> SkillStatusMap; class Quest; class Spell; -class Item; class WorldSession; enum PlayerSlots @@ -650,7 +652,7 @@ enum PlayerSlots // first slot for item stored (in any way in player m_items data) PLAYER_SLOT_START = 0, // last+1 slot for item stored (in any way in player m_items data) - PLAYER_SLOT_END = 232, + PLAYER_SLOT_END = 105, PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) }; @@ -722,61 +724,49 @@ enum InventoryPackSlots : uint8 // 28 slots INVENTORY_SLOT_ITEM_END = 63 }; -enum BankItemSlots // 28 slots -{ - BANK_SLOT_ITEM_START = 63, - BANK_SLOT_ITEM_END = 91 -}; - -enum BankBagSlots // 7 slots +enum BankBagSlots // 6 slots { - BANK_SLOT_BAG_START = 91, - BANK_SLOT_BAG_END = 98 + BANK_SLOT_BAG_START = 63, + BANK_SLOT_BAG_END = 69 }; enum BuyBackSlots // 12 slots { // stored in m_buybackitems - BUYBACK_SLOT_START = 98, - BUYBACK_SLOT_END = 110 -}; - -enum ReagentSlots // 98 slots -{ - REAGENT_SLOT_START = 110, - REAGENT_SLOT_END = 208, + BUYBACK_SLOT_START = 69, + BUYBACK_SLOT_END = 81 }; enum ChildEquipmentSlots { - CHILD_EQUIPMENT_SLOT_START = 208, - CHILD_EQUIPMENT_SLOT_END = 211, + CHILD_EQUIPMENT_SLOT_START = 81, + CHILD_EQUIPMENT_SLOT_END = 84, }; enum EquipableSpellSlots { - EQUIPABLE_SPELL_OFFENSIVE_SLOT1 = 211, - EQUIPABLE_SPELL_OFFENSIVE_SLOT2 = 212, - EQUIPABLE_SPELL_OFFENSIVE_SLOT3 = 213, - EQUIPABLE_SPELL_OFFENSIVE_SLOT4 = 214, - EQUIPABLE_SPELL_UTILITY_SLOT1 = 215, - EQUIPABLE_SPELL_UTILITY_SLOT2 = 216, - EQUIPABLE_SPELL_UTILITY_SLOT3 = 217, - EQUIPABLE_SPELL_UTILITY_SLOT4 = 218, - EQUIPABLE_SPELL_DEFENSIVE_SLOT1 = 219, - EQUIPABLE_SPELL_DEFENSIVE_SLOT2 = 220, - EQUIPABLE_SPELL_DEFENSIVE_SLOT3 = 221, - EQUIPABLE_SPELL_DEFENSIVE_SLOT4 = 222, - EQUIPABLE_SPELL_WEAPON_SLOT1 = 223, - EQUIPABLE_SPELL_WEAPON_SLOT2 = 224, - EQUIPABLE_SPELL_WEAPON_SLOT3 = 225, - EQUIPABLE_SPELL_WEAPON_SLOT4 = 226, + EQUIPABLE_SPELL_OFFENSIVE_SLOT1 = 84, + EQUIPABLE_SPELL_OFFENSIVE_SLOT2 = 85, + EQUIPABLE_SPELL_OFFENSIVE_SLOT3 = 86, + EQUIPABLE_SPELL_OFFENSIVE_SLOT4 = 87, + EQUIPABLE_SPELL_UTILITY_SLOT1 = 88, + EQUIPABLE_SPELL_UTILITY_SLOT2 = 89, + EQUIPABLE_SPELL_UTILITY_SLOT3 = 90, + EQUIPABLE_SPELL_UTILITY_SLOT4 = 91, + EQUIPABLE_SPELL_DEFENSIVE_SLOT1 = 92, + EQUIPABLE_SPELL_DEFENSIVE_SLOT2 = 93, + EQUIPABLE_SPELL_DEFENSIVE_SLOT3 = 94, + EQUIPABLE_SPELL_DEFENSIVE_SLOT4 = 95, + EQUIPABLE_SPELL_WEAPON_SLOT1 = 96, + EQUIPABLE_SPELL_WEAPON_SLOT2 = 97, + EQUIPABLE_SPELL_WEAPON_SLOT3 = 98, + EQUIPABLE_SPELL_WEAPON_SLOT4 = 99, }; enum AccountBankBagSlots { - ACCOUNT_BANK_SLOT_BAG_START = 227, - ACCOUNT_BANK_SLOT_BAG_END = 232 + ACCOUNT_BANK_SLOT_BAG_START = 100, + ACCOUNT_BANK_SLOT_BAG_END = 105 }; struct ItemPosCount @@ -810,14 +800,17 @@ enum class ItemSearchCallbackResult enum class BagSlotFlags : uint32 { - None = 0x00, - DisableAutoSort = 0x01, - PriorityEquipment = 0x02, - PriorityConsumables = 0x04, - PriorityTradeGoods = 0x08, - PriorityJunk = 0x10, - PriorityQuestItems = 0x20, - ExcludeJunkSell = 0x40, + None = 0x0000, + DisableAutoSort = 0x0001, + PriorityEquipment = 0x0002, + PriorityConsumables = 0x0004, + PriorityTradeGoods = 0x0008, + PriorityJunk = 0x0010, + PriorityQuestItems = 0x0020, + ExcludeJunkSell = 0x0040, + PriorityReagents = 0x0080, + ExpansionCurrent = 0x0100, + ExpansionLegacy = 0x0200, }; DEFINE_ENUM_FLAG(BagSlotFlags); @@ -939,7 +932,6 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS, PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS, - PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE, PLAYER_LOGIN_QUERY_LOAD_CURRENCY, PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, @@ -953,6 +945,7 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_TRAIT_CONFIGS, PLAYER_LOGIN_QUERY_LOAD_DATA_ELEMENTS, PLAYER_LOGIN_QUERY_LOAD_DATA_FLAGS, + PLAYER_LOGIN_QUERY_LOAD_BANK_TAB_SETTINGS, MAX_PLAYER_LOGIN_QUERY }; @@ -1084,29 +1077,6 @@ struct BGData bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; } }; -struct VoidStorageItem -{ - VoidStorageItem() : ItemId(0), ItemEntry(0), RandomBonusListId(0), FixedScalingLevel(0), ArtifactKnowledgeLevel(0), Context(ItemContext::NONE) { } - VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, ItemRandomBonusListId randomBonusListId, - uint32 fixedScalingLevel, uint32 artifactKnowledgeLevel, ItemContext context, std::vector<int32> const& bonuses) - : ItemId(id), ItemEntry(entry), CreatorGuid(creator), RandomBonusListId(randomBonusListId), - FixedScalingLevel(fixedScalingLevel), ArtifactKnowledgeLevel(artifactKnowledgeLevel), Context(context) - { - BonusListIDs.insert(BonusListIDs.end(), bonuses.begin(), bonuses.end()); - } - VoidStorageItem(VoidStorageItem&& vsi) noexcept : ItemId(vsi.ItemId), ItemEntry(vsi.ItemEntry), CreatorGuid(vsi.CreatorGuid), RandomBonusListId(vsi.RandomBonusListId), - FixedScalingLevel(vsi.FixedScalingLevel), ArtifactKnowledgeLevel(vsi.ArtifactKnowledgeLevel), Context(vsi.Context), BonusListIDs(std::move(vsi.BonusListIDs)) { } - - uint64 ItemId; - uint32 ItemEntry; - ObjectGuid CreatorGuid; - ItemRandomBonusListId RandomBonusListId; - uint32 FixedScalingLevel; - uint32 ArtifactKnowledgeLevel; - ItemContext Context; - std::vector<int32> BonusListIDs; -}; - struct ResurrectionData { ObjectGuid GUID; @@ -1391,11 +1361,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> if (flag.HasFlag(ItemSearchLocation::Bank)) { - for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (callback(pItem) == ItemSearchCallbackResult::Stop) - return false; - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) if (Bag* pBag = GetBagByPos(i)) for (uint32 j = 0; j < GetBagSize(pBag); ++j) @@ -1412,11 +1377,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> if (Item* pItem = GetItemInBag(bag, j)) if (callback(pItem) == ItemSearchCallbackResult::Stop) return false; - - for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) - if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (callback(pItem) == ItemSearchCallbackResult::Stop) - return false; } return true; @@ -1450,16 +1410,37 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> static bool IsBagPos(uint16 pos); static bool IsBankPos(uint16 pos) { return IsBankPos(pos >> 8, pos & 255); } static bool IsBankPos(uint8 bag, uint8 slot); - static bool IsReagentBankPos(uint16 pos) { return IsReagentBankPos(pos >> 8, pos & 255); } - static bool IsReagentBankPos(uint8 bag, uint8 slot); static bool IsChildEquipmentPos(uint16 pos) { return IsChildEquipmentPos(pos >> 8, pos & 255); } static bool IsChildEquipmentPos(uint8 bag, uint8 slot); + static bool IsAccountBankPos(uint16 pos) { return IsBankPos(pos >> 8, pos & 255); } + static bool IsAccountBankPos(uint8 bag, uint8 slot); bool IsValidPos(uint16 pos, bool explicit_pos) const { return IsValidPos(pos >> 8, pos & 255, explicit_pos); } bool IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const; uint8 GetInventorySlotCount() const { return m_activePlayerData->NumBackpackSlots; } void SetInventorySlotCount(uint8 slots); uint8 GetBankBagSlotCount() const { return m_activePlayerData->NumBankSlots; } void SetBankBagSlotCount(uint8 count) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::NumBankSlots), count); } + uint8 GetCharacterBankTabCount() const { return m_activePlayerData->NumCharacterBankTabs; } + void SetCharacterBankTabCount(uint8 count) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::NumCharacterBankTabs), count); } + uint8 GetAccountBankTabCount() const { return m_activePlayerData->NumAccountBankTabs; } + void SetAccountBankTabCount(uint8 count) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::NumAccountBankTabs), count); } + void SetCharacterBankTabSettings(uint32 tabId, std::string const& name, std::string const& icon, std::string const& description, BagSlotFlags depositFlags) + { + auto setter = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CharacterBankTabSettings, tabId); + SetBankTabSettings(setter, name, icon, description, depositFlags); + } + void SetAccountBankTabSettings(uint32 tabId, std::string const& name, std::string const& icon, std::string const& description, BagSlotFlags depositFlags) + { + auto setter = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::AccountBankTabSettings, tabId); + SetBankTabSettings(setter, name, icon, description, depositFlags); + } + void SetBankTabSettings(UF::MutableFieldReferenceWithChangesMask<UF::BankTabSettings, false> setter, std::string const& name, std::string const& icon, std::string const& description, BagSlotFlags depositFlags) + { + SetUpdateFieldValue(setter.ModifyValue(&UF::BankTabSettings::Name), name); + SetUpdateFieldValue(setter.ModifyValue(&UF::BankTabSettings::Icon), icon); + SetUpdateFieldValue(setter.ModifyValue(&UF::BankTabSettings::Description), description); + SetUpdateFieldValue(setter.ModifyValue(&UF::BankTabSettings::DepositFlags), int32(depositFlags)); + } bool IsBackpackAutoSortDisabled() const { return m_activePlayerData->BackpackAutoSortDisabled; } void SetBackpackAutoSortDisabled(bool disabled) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BackpackAutoSortDisabled), disabled); } bool IsBackpackSellJunkDisabled() const { return m_activePlayerData->BackpackSellJunkDisabled; } @@ -1470,10 +1451,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void SetBagSlotFlag(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BagSlotFlags, bagIndex), flags.AsUnderlyingType()); } void RemoveBagSlotFlag(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BagSlotFlags, bagIndex), flags.AsUnderlyingType()); } void ReplaceAllBagSlotFlags(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BagSlotFlags, bagIndex), flags.AsUnderlyingType()); } - EnumFlag<BagSlotFlags> GetBankBagSlotFlags(uint32 bagIndex) const { return static_cast<BagSlotFlags>(m_activePlayerData->BankBagSlotFlags[bagIndex]); } - void SetBankBagSlotFlag(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BankBagSlotFlags, bagIndex), flags.AsUnderlyingType()); } - void RemoveBankBagSlotFlag(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BankBagSlotFlags, bagIndex), flags.AsUnderlyingType()); } - void ReplaceAllBankBagSlotFlags(uint32 bagIndex, EnumFlag<BagSlotFlags> flags) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::BankBagSlotFlags, bagIndex), flags.AsUnderlyingType()); } bool HasItemCount(uint32 item, uint32 count = 1, bool inBankAlso = false) const; bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = nullptr) const; bool CanNoReagentCast(SpellInfo const* spellInfo) const; @@ -1998,6 +1975,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void ApplyTraitConfig(int32 configId, bool apply); void ApplyTraitEntry(int32 traitNodeEntryId, int32 rank, int32 grantedRanks, bool apply); void SetActiveCombatTraitConfigID(int32 traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ActiveCombatTraitConfigID), traitConfigId); } + void SetCurrentCombatTraitConfigSubTreeID(int32 traitSubTreeId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::CurrentCombatTraitConfigSubTreeID), traitSubTreeId); } void SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild); void SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig); Optional<PlayerSpellTrait> GetTraitInfoForSpell(uint32 spellId) const; @@ -2807,18 +2785,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> std::string GetMapAreaAndZoneString() const; std::string GetCoordsMapAreaAndZoneString() const; - // Void Storage - bool IsVoidStorageUnlocked() const { return HasPlayerFlag(PLAYER_FLAGS_VOID_UNLOCKED); } - void UnlockVoidStorage() { SetPlayerFlag(PLAYER_FLAGS_VOID_UNLOCKED); } - void LockVoidStorage() { RemovePlayerFlag(PLAYER_FLAGS_VOID_UNLOCKED); } - uint8 GetNextVoidStorageFreeSlot() const; - uint8 GetNumOfVoidStorageFreeSlots() const; - uint8 AddVoidStorageItem(VoidStorageItem&& item); - void DeleteVoidStorageItem(uint8 slot); - bool SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot); - VoidStorageItem* GetVoidStorageItem(uint8 slot) const; - VoidStorageItem* GetVoidStorageItem(uint64 id, uint8& slot) const; - // Reagent Bank bool IsReagentBankUnlocked() const { return HasPlayerFlagEx(PLAYER_FLAGS_EX_REAGENT_BANK_UNLOCKED); } void UnlockReagentBank() { SetPlayerFlagEx(PLAYER_FLAGS_EX_REAGENT_BANK_UNLOCKED); } @@ -3058,7 +3024,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult, uint32 timeDiff); - void _LoadVoidStorage(PreparedQueryResult result); void _LoadMail(PreparedQueryResult mailsResult, PreparedQueryResult mailItemsResult, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult); static Item* _LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint64 mailId, Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData); @@ -3090,6 +3055,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void _LoadCurrency(PreparedQueryResult result); void _LoadCUFProfiles(PreparedQueryResult result); void _LoadPlayerData(PreparedQueryResult elementsResult, PreparedQueryResult flagsResult); + void _LoadCharacterBankTabSettings(PreparedQueryResult result); /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -3099,7 +3065,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void _SaveActions(CharacterDatabaseTransaction trans); void _SaveAuras(CharacterDatabaseTransaction trans); void _SaveInventory(CharacterDatabaseTransaction trans); - void _SaveVoidStorage(CharacterDatabaseTransaction trans); void _SaveMail(CharacterDatabaseTransaction trans); void _SaveQuestStatus(CharacterDatabaseTransaction trans); void _SaveDailyQuestStatus(CharacterDatabaseTransaction trans); @@ -3119,6 +3084,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void _SaveCurrency(CharacterDatabaseTransaction trans); void _SaveCUFProfiles(CharacterDatabaseTransaction trans); void _SavePlayerData(CharacterDatabaseTransaction trans); + void _SaveCharacterBankTabSettings(CharacterDatabaseTransaction trans) const; /*********************************************************/ /*** ENVIRONMENTAL SYSTEM ***/ @@ -3151,8 +3117,6 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> PlayerCurrenciesMap _currencyStorage; - VoidStorageItem* _voidStorageItems[VOID_STORAGE_MAX_SLOT]; - std::vector<Item*> m_itemUpdateQueue; bool m_itemUpdateQueueBlocked; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f6917ee88f7..ab91bf1f62b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1433,6 +1433,12 @@ class TC_GAME_API Unit : public WorldObject void SetChannelObject(uint32 slot, ObjectGuid guid); void RemoveChannelObject(ObjectGuid guid); void ClearChannelObjects(); + void SetChannelSpellData(uint32 startTimeMs, uint32 durationMs) + { + auto channelData = m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ChannelData); + SetUpdateFieldValue(channelData.ModifyValue(&UF::UnitChannel::StartTimeMs), startTimeMs); + SetUpdateFieldValue(channelData.ModifyValue(&UF::UnitChannel::Duration), durationMs); + } int8 GetSpellEmpowerStage() const { return m_unitData->SpellEmpowerStage; } void SetSpellEmpowerStage(int8 stage) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::SpellEmpowerStage), stage); } |
