// Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. using Framework.Constants; using Game.Maps; using Game.Networking; using Game.Networking.Packets; using System.Collections.Generic; namespace Game.Entities { public class MeshObject : WorldObject { MeshObjectData m_meshObjectData; Position _stationaryPosition = new(); public MeshObject(bool isWorldObject = false) : base(isWorldObject) { ObjectTypeMask |= TypeMask.MeshObject; ObjectTypeId = TypeId.MeshObject; m_updateFlag.Stationary = true; m_updateFlag.MeshObject = true; m_entityFragments.Add(EntityFragment.Tag_MeshObject, false); m_meshObjectData = new(); _stationaryPosition = new(); } public override void AddToWorld() { if (!IsInWorld) { GetMap().GetObjectsStore().Add(GetGUID(), this); base.AddToWorld(); } } public override void RemoveFromWorld() { if (IsInWorld) { base.RemoveFromWorld(); GetMap().GetObjectsStore().Remove(GetGUID()); } } public static MeshObject CreateMeshObject(Map map, Position pos, ObjectGuid privateObjectOwner) { if (map == null) return null; ulong lowGuid = map.GenerateLowGuid(HighGuid.MeshObject); MeshObject meshObject = new(); if (!meshObject.Create(lowGuid, map, pos, privateObjectOwner)) { meshObject.Dispose(); return null; } return meshObject; } bool Create(ulong lowGuid, Map map, Position pos, ObjectGuid privateObjectOwner) { SetMap(map); Relocate(pos); RelocateStationaryPosition(pos); SetPrivateObjectOwner(privateObjectOwner); _Create(ObjectGuid.Create(HighGuid.MeshObject, GetMapId(), 0, lowGuid)); SetObjectScale(1.0f); // Register the updateable mesh-object-data fragment (vendor-style updateable fragment). m_entityFragments.Add(EntityFragment.FMeshObjectData_C, IsInWorld); if (!GetMap().AddToMap(this)) return false; return true; } public override void BuildValuesCreate(WorldPacket data, UpdateFieldFlag flags, Player target) { m_objectData.WriteCreate(data, flags, this, target); if (m_meshObjectData != null) { if (EntityFragmentsHolder.IsIndirectFragment(EntityFragment.FMeshObjectData_C)) data.WriteUInt8(1); // IndirectFragmentActive: FMeshObjectData_C m_meshObjectData.WriteCreate(data, flags, this, target); } } public override void BuildValuesUpdate(WorldPacket data, UpdateFieldFlag flags, Player target) { if ((m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(EntityFragment.CGObject)) != 0) { data.WriteUInt32(m_values.GetChangedObjectTypeMask()); if (m_values.HasChanged(TypeId.Object)) m_objectData.WriteUpdate(data, flags, this, target); } if (m_meshObjectData != null && (m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(EntityFragment.FMeshObjectData_C)) != 0) m_meshObjectData.WriteUpdate(data, flags, this, target); } void BuildValuesUpdateForPlayerWithMask(UpdateData data, UpdateMask requestedObjectMask, UpdateMask requestedMeshObjectMask, Player target) { UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); UpdateMask valuesMask = new((int)TypeId.Max); if (requestedObjectMask.IsAnySet()) valuesMask.Set((int)TypeId.Object); WorldPacket buffer = new(); BuildEntityFragmentsForValuesUpdateForPlayerWithMask(buffer, flags); buffer.WriteUInt32(valuesMask.GetBlock(0)); if (valuesMask[(int)TypeId.Object]) m_objectData.WriteUpdate(buffer, requestedObjectMask, true, this, target); // MeshObjectData is an updateable fragment (FMeshObjectData_C), written after the values block. if (m_meshObjectData != null && requestedMeshObjectMask.IsAnySet()) m_meshObjectData.WriteUpdate(buffer, requestedMeshObjectMask, true, this, target); WorldPacket buffer1 = new(); buffer1.WriteUInt8((byte)UpdateType.Values); buffer1.WritePackedGuid(GetGUID()); buffer1.WriteUInt32(buffer.GetSize()); buffer1.WriteBytes(buffer.GetData()); data.AddUpdateBlock(buffer1); } public override void ClearUpdateMask(bool remove) { m_values.ClearChangesMask(m_meshObjectData); base.ClearUpdateMask(remove); } public override uint GetFaction() { return 0; } public override Position GetStationaryPosition() { return _stationaryPosition; } void RelocateStationaryPosition(Position pos) { _stationaryPosition.Relocate(pos); } class ValuesUpdateForPlayerWithMaskSender { MeshObject Owner; ObjectFieldData ObjectMask = new(); MeshObjectData MeshObjectMask = new(); public ValuesUpdateForPlayerWithMaskSender(MeshObject owner) { Owner = owner; } public void Invoke(Player player) { UpdateData udata = new(Owner.GetMapId()); Owner.BuildValuesUpdateForPlayerWithMask(udata, ObjectMask.GetUpdateMask(), MeshObjectMask.GetUpdateMask(), player); udata.BuildPacket(out UpdateObject packet); player.SendPacket(packet); } public static implicit operator IDoWork(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke; } } }